• [模拟赛]棘手的操作



    这道题是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
    ",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
    ",pre = an + all);
    			} else printf("%d
    ",pre = maxl[q] + all);
    		}
    	}
    	//for(;;);
    	return 0;
    }


  • 相关阅读:
    【水】希望之花
    如何不用狄利克雷卷积证明莫比乌斯函数性质二
    【数学】gcd
    挂分宝典
    [luogu P6042]「ACOI2020」学园祭 题解
    [luogu P6041]「ACOI2020」布丁暗杀计划 题解
    11.19模拟
    「CSP-S2020」题解
    11.11模拟
    「洛谷P1445」樱花
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/5353664.html
Copyright © 2020-2023  润新知