[CSP-S模拟测试]:Weed(线段树)


题目描述

$duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹。
为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验。
电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为$v_i$的金坷垃,或者除掉最新$v_i$层(不是量)撒的金坷垃。如果上面只留有不足$v_i$层金坷垃,那么就相当于电脑上面没有金坷垃了。
$duyege$非常严谨,一开始先给你$m$个上述操作要你依次完成。然后又对实验步骤进行了$q$次更改,每次更改都会改变其中一个操作为另外一个操作。每次修改之后都会询问最终金坷垃的量有多少。


输入格式

输入第一行为两个正整数$m$、$q$,接下来$m$行每行$2$个整数$k$、$v_i$。$k$为$0$时撒金坷垃,为$1$时除金坷垃。接下来$q$行每行$3$个整数$c_i$、$k$、$v_i$,$c_i$代表被更改的操作是第$c_i$个,后面$2$个数描述更改为这样的操作。


输出格式

输出$q$行代表每次金坷垃的量为多少。


样例

样例输入

10 5
0 10
1 5
0 13
0 18
0 2
1 1
0 8
0 9
1 3
0 7
9 0 3
10 1 7
6 0 8
10 0 5
8 1 2

样例输出

58
0
0
66
41


数据范围与提示

对于$30%$的数据$m\leqslant 1,000,q\leqslant 1,000$。
对于另外$20%$的数据,每次$k=1$时都会将金坷垃清空。
对于$100%$的数据,$m\leqslant 2\times {10}^5,q\leqslant 2\times {10}^5,v_i\leqslant {10}^4$。


题解

首先,来解释一下题意,在更改操作之后就不改回来啦。

$30%$算法:

暴力修改,每次都暴力扫一遍统计答案。

时间复杂度:$\Theta(m\times q)$。

期望得分:$30$分。

实际得分:$30$分。

$100%$算法:

利用线段树维护以下四个值:

$\alpha.$区间内加数总和$sum$。

$\beta.$当前区间向前删除数字的数量$del$。

$gamma.$当前区间内“净”加的元素数$add$。

$delta.$当前区间被右兄弟删除后的总和$fla$(只对左儿子维护这个信息即可)。

每次询问就是输出$sum[1]$。

之后就是代码实现的问题了,主要是$pushup$函数比较难搞。

时间复杂度:$\Theta(N\log N+Q\log^2N)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

$30%$算法:

#include<bits/stdc++.h>
using namespace std;
int m,q;
pair<bool,int> e[200001];
int sta[200001],top;
int ans;
int main()
{
	scanf("%d%d",&m,&q);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&e[i].first,&e[i].second);
	while(q--)
	{
		ans=0;
		top=0;
		int c,k,v;
		scanf("%d%d%d",&c,&k,&v);
		e[c]=make_pair(k,v);
		for(int i=1;i<=m;i++)
			if(e[i].first==1)for(int j=1;j<=e[i].second;j++)if(top)top--;else break;
			else sta[++top]=e[i].second;
		for(int i=1;i<=top;i++)ans+=sta[i];
		printf("%d\n",ans);
	}
	return 0;
}

$100%$算法:

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int m,q;
int c,k,v;
pair<bool,int> e[200001];
int tradd[1000000],trdel[1000000],trfla[1000000],trsum[1000000];
int ask(int x,int w)
{
	if(w<tradd[R(x)])return trfla[L(x)]+ask(R(x),w);
	if(w==tradd[R(x)])return trfla[L(x)];
	if(w>tradd[R(x)])return ask(L(x),w-tradd[R(x)]+trdel[R(x)]);
}
void pushup(int x)
{
	if(tradd[L(x)]<=trdel[R(x)])
	{
		trfla[L(x)]=0;
		tradd[x]=tradd[R(x)];
		trdel[x]=trdel[L(x)]+trdel[R(x)]-tradd[L(x)];
		trsum[x]=trsum[R(x)];
	}
	else
	{
		if(trdel[R(x)])trfla[L(x)]=ask(L(x),trdel[R(x)]);
		else trfla[L(x)]=trsum[L(x)];
		tradd[x]=tradd[L(x)]+tradd[R(x)]-trdel[R(x)];
		trdel[x]=trdel[L(x)];
		trsum[x]=trfla[L(x)]+trsum[R(x)];
	}
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		if(e[l].first)trdel[x]=e[l].second;
		else
		{
			tradd[x]=1;
			trsum[x]=e[l].second;
			trfla[x]=e[l].second;
		}
		return;
	}
	int mid=(l+r)>>1;
	build(L(x),l,mid);
	build(R(x),mid+1,r);
	pushup(x);
}
void clear(int x){tradd[x]=trdel[x]=trsum[x]=trfla[x]=0;}
void change(int x,int l,int r,int w)
{
	if(l==r)
	{
		clear(x);
		if(e[l].first)trdel[x]=e[l].second;
		else
		{
			tradd[x]=1;
			trsum[x]=e[l].second;
			trfla[x]=e[l].second;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(w<=mid)change(L(x),l,mid,w);
	else change(R(x),mid+1,r,w);
	pushup(x);
}
int main()
{
	scanf("%d%d",&m,&q);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&e[i].first,&e[i].second);
	build(1,1,m);
	while(q--)
	{
		scanf("%d%d%d",&c,&k,&v);
		e[c]=make_pair(k,v);
		change(1,1,m,c);
		printf("%d\n",trsum[1]);
	}
	return 0;
}

rp++

优质内容筛选与推荐>>
1、搬家2015-05-25
2、ASP.NET 2.0防止同一用户同时登陆
3、hql语句关联查询(select new )
4、csps模拟68d,e,f题解
5、.NET Framework 4下的ResolveUrl和ResolveClientUrl的改变


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn