zoukankan      html  css  js  c++  java
  • BZOJ2333: [SCOI2011]棘手的操作

    BZOJ2333: [SCOI2011]棘手的操作

    Description

    N个节点,标号从1N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:

    U x y: 加一条边,连接第x个节点和第y个节点

    A1 x v: 将第x个节点的权值增加v

    A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v

    A3 v: 将所有节点的权值都增加v

    F1 x: 输出第x个节点当前的权值

    F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值

    F3: 输出所有节点中,权值最大的节点的权值

    Input

    输入的第一行是一个整数N,代表节点个数。

    接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。

    再下一行输入一个整数Q,代表接下来的操作数。

    最后输入Q行,每行的格式如题目描述所示。

    Output

    对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

    Sample Input

    3
    0 0 0
    8
    A1 3 -20
    A1 2 20
    U 1 3
    A2 1 10
    F1 3
    F2 3
    A3 -10
    F3

    Sample Output

    -10
    10
    10

    HINT

     对于30%的数据,保证 N<=100,Q<=10000

    对于80%的数据,保证 N<=100000,Q<=100000

    对于100%的数据,保证 N<=300000,Q<=300000

    对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

    题解Here!

    这些操作的确棘手。。。

    第一想法:LCT

    但是 LCT 不能求出 x 所在联通块,更不能修改。

    又看到了 求最大权值 ,于是想到了 左偏树

    1.合并两个堆:直接merge

    2.把某个点加:把这个点删了,再加一个更新了权值之后的点。

    3.整个堆加:在根上打mark

    4.全局加:记个全局mark

    5.查询单点:一路加上所有父亲的mark再输出

    6.查询堆最大值:直接输出

    7.查询全局最大值:

    第七个操作需要把所有堆的根提取出来再建个堆。

    每次merge都要把并进去的堆删掉,单点加和整堆加都需要更新最大值。

    删除操作:我们先和删除最值一样,把它的孩子合并起来。

    因为我们合并后的新树的距离可能会改变,所以要更新一下q的距离。

    假如q的距离是p的距离+1,那么无论p是左右子树都不需要调整。

    假如p的距离+1小于q的距离,就改下q的距离,而且假如p是左子树的话需要交换子树。

    由于q的距离小了,还需要更新它的父亲。

    假如p距离变大了的话,看看p是不是左子树,是左子树的话就结束了。

    但是p是右子树的话,就有两种可能,假如p的距离仍然小于q的左子树,那就直接改q的距离就好了;大于的话还要换下子树,向上走。

    (在这里还有一种情况就是原来的左右子树距离一样,那就不用更新q的距离,直接结束就好了)

    注:OIer们会被调试逼疯的。。。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 300010
    using namespace std;
    int n,m,addall=0,root;
    struct tree{
    	struct node{
    		int son[2];
    		int v,dis,f,flag;
    	}a[MAXN];
    	inline void independent(int rt){
    		a[rt].son[0]=a[rt].son[1]=a[rt].f=0;
    	}
    	inline void pushdown(int rt){
    		if(a[rt].son[0]){
    			a[a[rt].son[0]].v+=a[rt].flag;
    			a[a[rt].son[0]].flag+=a[rt].flag;
    		}
    		if(a[rt].son[1]){
    			a[a[rt].son[1]].v+=a[rt].flag;
    			a[a[rt].son[1]].flag+=a[rt].flag;
    		}
    		a[rt].flag=0;
    	}
    	int merge(int x,int y){
    		if(!x)return y;if(!y)return x;
    		if(a[x].v<a[y].v)swap(x,y);
    		pushdown(x);
    		a[x].son[1]=merge(a[x].son[1],y);
    		a[a[x].son[1]].f=x;
    		if(a[a[x].son[1]].dis>a[a[x].son[0]].dis)swap(a[x].son[0],a[x].son[1]);
    		a[x].dis=a[a[x].son[1]].dis+1;
    		return x;
    	}
    	int find(int x){
    		while(a[x].f)x=a[x].f;
    		return x;
    	}
    	int sum(int rt){
    		int s=0;
    		for(int i=a[rt].f;i;i=a[i].f)s+=a[i].flag;
    		return s;
    	}
    	int deletemin(int rt){
    		pushdown(rt);
    		int x=a[rt].f,y=merge(a[rt].son[0],a[rt].son[1]);
    		a[y].f=x;
    		if(x)a[x].son[a[x].son[1]==rt]=y;
    		while(x){
    			if(a[a[x].son[0]].dis<a[a[x].son[1]].dis)swap(a[x].son[0],a[x].son[1]);
    			if(a[a[x].son[1]].dis+1==a[x].dis)return root;
    			a[x].dis=a[a[x].son[1]].dis+1;
    			y=x;
    			x=a[x].f;
    		}
    		return y;
    	}
    	inline void addtree(int x,int v){
    		x=find(x);
    		a[x].v+=v;
    		a[x].flag+=v;
    	}
    	int insert(int x,int v){
    		int f=find(x);
    		if(f==x){
    			if(!a[x].son[0]&&!a[x].son[1]){
    				a[x].v+=v;
    				return x;
    			}
    			else{
    				if(a[x].son[0])f=a[x].son[0];
    				else f=a[x].son[1];
    			}
    		}
    		deletemin(x);
    		a[x].v+=v+sum(x);
    		independent(x);
    		return merge(find(f),x);
    	}
    	int buildtree(){
    		queue<int> q;
    		for(int i=1;i<=n;i++)q.push(i);
    		while(q.size()>1){
    			int x,y,z;
    			x=q.front();q.pop();
    			y=q.front();q.pop();
    			z=merge(x,y);
    			q.push(z);
    		}
    		return q.front();
    	}
    }one,two;
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    int main(){
    	char ch[2];
    	int x,y,k;
    	n=read();
    	one.a[0].dis=two.a[0].dis=-1;
    	for(int i=1;i<=n;i++)one.a[i].v=two.a[i].v=read();
    	root=two.buildtree();
    	m=read();
    	while(m--){
    		scanf("%s",ch);
    		switch(ch[0]){
    			case 'U':{
    				x=read();y=read();
    				x=one.find(x);y=one.find(y);
    				if(x!=y){
    					k=one.merge(x,y);
    					if(k==x)root=two.deletemin(y);
    					else root=two.deletemin(x);
    				}
    				break;
    			}
    			case 'A':{
    				x=read();
    				switch(ch[1]){
    					case '1':{
    						y=read();
    						root=two.deletemin(one.find(x));
    						k=one.insert(x,y);
    						two.a[k].v=one.a[k].v;
    						two.independent(k);
    						root=two.merge(root,k);
    						break;
    					}
    					case '2':{
    						y=read();
    						int f=one.find(x);
    						root=two.deletemin(f);
    						one.a[f].v+=y;
    						one.a[f].flag+=y;
    						two.a[f].v=one.a[f].v;
    						two.independent(f);
    						root=two.merge(root,f);
    						break;
    					}
    					case '3':addall+=x;break;
    				}
    				break;
    			}
    			case 'F':{
    				switch(ch[1]){
    					case '1':{
    						x=read();
    						printf("%d
    ",one.a[x].v+addall+one.sum(x));
    						break;
    					}
    					case '2':{
    						x=read();
    						x=one.find(x);
    						printf("%d
    ",one.a[x].v+addall);
    						break;
    					}
    					case '3':{
    						printf("%d
    ",two.a[root].v+addall);
    						break;
    					}
    				}
    				break;
    			}
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    智能移动机器人背后蕴含的技术——激光雷达
    Kalman Filters
    Fiddler抓HttpClient的包
    VSCode开发WebApi EFCore的坑
    WPF之小米Logo超圆角的实现
    windows react打包发布
    jenkins in docker踩坑汇总
    Using ML.NET in Jupyter notebooks 在jupyter notebook中使用ML.NET ——No design time or full build available
    【Linux知识点】CentOS7 更换阿里云源
    【Golang 报错】exec gcc executable file not found in %PATH%
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9032387.html
Copyright © 2011-2022 走看看