这道题是HugeGun出的一道题(据说是他改编的,bzoj2333) 但原题很毒瘤啊,有负数,他说正解是堆套堆Orz。
作为什么也不会的蒟蒻,看到这个瞬间想到带权冰茶集(点权)。。。 (汪神说他写的是火茶集2333)
一开始开一个数组,表示这个点和他的子孙将要被加上的值(因为觉得像lazy思想,所以起名lazy)
对于修改所有结点,可以用一个变量来存取,输出时加上即可,对于修改单点,直接加在那个点上更新下当前所在集合的最大值,
对于修改集合,将值加在点所在集合的代表元的lazy上就行了。。。
合并两个集合时,假设这两个集合的代表元为x,y,那么lazy[x] 应减去 Lazy[y] 。 因为显然现在lazy[y]中的数跟x所在集合没有半毛钱关系,而x集合中的点在合并后会加上lazy[y],所以应在lazy[x]中减去lazy[y]....
That is all 。。。。。
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
const int N = 1e6+7;
int n,Q,f[N];
char lz[10];
int w[N],laz[N],pre,all,maxl[N],suf; //马克思
int stk[N],top;
int find (int x) {
if(f[f[x]] == f[x]) return f[x];
int ret = x;
top = 0;
while(f[ret] != ret) stk[++top] = ret,ret = f[ret];
for(int i=top-1;i;--i) laz[stk[i]] += laz[stk[i+1]] , f[stk[i]] = ret;
return ret;
}
void merge (int x,int y) {
int l = find (x), r = find (y);
if(l == r) return ;
maxl[r] = std :: max (maxl[r],maxl[l]);
f[l] = r;
laz[l] -= laz[r];
}
int main () {
freopen("operation.in","r",stdin);
freopen("operation.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&w[i]) ,maxl[i] = w[i], f[i] = i, suf = std :: max(suf,w[i]);
scanf("%d",&Q);
while(Q--) {
scanf("%s",lz);
if(lz[0] == 'U') {
int x,y;
scanf("%d%d",&x,&y);
merge((x+pre)%n+1,(y+pre)%n+1);
} else if(lz[0] == 'A') {
int x,y;
scanf("%d",&x);
if(lz[1] == '3') all += x;
else {
scanf("%d",&y);
x = (x + pre) % n + 1;
int q = find(x);
if(lz[1] == '1') w[x] += y,maxl[q] = std :: max(maxl[q],w[x] + laz[x] + (x == q ? 0 : laz[q])) , suf = std :: max(maxl[q],suf);
else laz[q] += y , maxl[q] += y, suf = std :: max(suf,maxl[q]);
}
} else if(lz[0] == 'F') {
if(lz[1] == '3') {
printf("%d\n",pre = suf + all);
continue;
}
int x;
scanf("%d",&x); x = (x+pre)%n+1;
int q = find (x);
if(lz[1] == '1') {
int an = w[x];
an += laz[x] + (x == q ? 0 : laz[q]);
printf("%d\n",pre = an + all);
} else printf("%d\n",pre = maxl[q] + all);
}
}
//for(;;);
return 0;
}