题解 P4879 【ycz的妹子】
大吼一声:
遇事不决先分块
然后就狗在机子前一下午; 这道题,充分证明读题的重要性;
如果你仅仅以为这是一道单点修改,那么你就GG了;
首先,分析一下题面:
1,ycz的妹子(青梅竹马)起初在1—n号城市中;但是,由于ycz的魅力强大,序列后面的妹子也会冒出来,所以,干脆直接把范围定位5e5(广撒网,多捞鱼) 雾~ 。 咳咳,是题面保证的;
2,题面说会有负值,那么颜值为0的也会有咯;所以不要把权值作为有或无的标志,再开个数组存一下;
3,对于编号为C的修改,直接修改,注意把快内和顺带改一下;
4,对于编号为I的修改,因为一城不容二女(难道城市只有两室一厅那么大 雾 ),后来的会顶走前面的,也就是覆盖;所以对于这个修改,要分此城市之前有无妹子,有就直接覆盖,顺带改下快内和,而之前没有,那么块中的妹子个数要加加,并且此城市别打上标记;
5,丢与编号为D的修改,应为找的是第X个有妹子的,所以,我们就有已经维护好的块内妹子个数来跳,找到对应的块,修改如上,只是赋0而已;
6,询问就是块的和,简单一加就行
7,最后的提醒,要开long long,不然~呃呃,你知道的;
最后,奉上我的代码,不懂有注释:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 1000500
using namespace std;
int n,m;
long long a[N],cnt[N],siz[N];//妹子的颜值,是否有妹子,块内妹子数
int L[N],R[N],tag[N]; //分块的编号,左右端点;
long long sum[N];//妹子和
int len,opt;//撒网范围
//修改1,简单修改
inline void Change_C(int x,int y) {
if(!cnt[x]) return ;
sum[tag[x]] -= a[x];
a[x] -= y;
sum[tag[x]] += a[x];
}
//修改2,分类讨论一下,顺带维护
inline void Change_I(int x,int y) {
if(cnt[x]) {
sum[tag[x]] -= a[x];
a[x] = y;
sum[tag[x]] += a[x];
}
else {
cnt[x] = 1;
sum[tag[x]] -= a[x];
a[x] = y;
sum[tag[x]] += a[x];
siz[tag[x]] += 1;
}
}
//跳妹子,找块并修改
inline void Change_D(int x) {
int teg = 1;
while(x - siz[teg] > 0) x -= siz[teg],teg ++;
for(int i = L[teg];i <= R[teg];i ++) {
if(x - cnt[i] == 0){
siz[teg] --;
sum[teg] -= a[i];
cnt[i] = a[i] = 0;
//别忘赋0
return ;
}
else x -= cnt[i];
}
}
inline long long Qurry() {
long long res = 0;
for(int i = 1;i <= tag[opt];i ++)
res += sum[i];
return res;
}
int main() {
opt = 500000;//广撒网
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
scanf("%d",&a[i]),cnt[i] = 1;
//青梅竹马是喜欢ycz的,直接赋1
len = sqrt(opt);
for(int i = 1;i <= opt;i ++)
tag[i] = (i - 1) / len + 1;
for(int i = 1;i <= tag[opt];i ++)
L[i] = R[i - 1] + 1,R[i] = min(L[i] + len - 1,opt);
//处理左右端点
for(int i = 1;i <= tag[opt];i ++)
for(int j = L[i];j <= R[i];j ++)
sum[i] += a[j],siz[i] += cnt[j];
//分块预处理
for(int i = 1;i <= m;i ++) {
char s[3]; int x,y;
scanf("%s",s + 1);
if(s[1] == 'C') {
scanf("%d%d",&x,&y);
Change_C(x,y);
}
if(s[1] == 'I') {
scanf("%d%d",&x,&y);
Change_I(x,y);
}
if(s[1] == 'D') {
scanf("%d",&x);
Change_D(x);
}
if(s[1] == 'Q')
printf("%lld\n",Qurry());
}
return 0;
}
希望可以帮到大家; 喜欢分块————> 点我
Update
之前代码有锅,已修改,给大家带来不便请谅解QAQ