题目描述
$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%$的数据$mleqslant 1,000,qleqslant 1,000$。
对于另外$20%$的数据,每次$k=1$时都会将金坷垃清空。
对于$100%$的数据,$mleqslant 2 imes {10}^5,qleqslant 2 imes {10}^5,v_ileqslant {10}^4$。
题解
首先,来解释一下题意,在更改操作之后就不改回来啦。
$30%$算法:
暴力修改,每次都暴力扫一遍统计答案。
时间复杂度:$Theta(m imes q)$。
期望得分:$30$分。
实际得分:$30$分。
$100%$算法:
利用线段树维护以下四个值:
$alpha.$区间内加数总和$sum$。
$eta.$当前区间向前删除数字的数量$del$。
$gamma.$当前区间内“净”加的元素数$add$。
$delta.$当前区间被右兄弟删除后的总和$fla$(只对左儿子维护这个信息即可)。
每次询问就是输出$sum[1]$。
之后就是代码实现的问题了,主要是$pushup$函数比较难搞。
时间复杂度:$Theta(Nlog N+Qlog^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
",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
",trsum[1]);
}
return 0;
}
rp++