题目描述
$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++
来源:https://www.cnblogs.com/wzc521/p/11335541.html