• HDU 5002 Tree


    传送门
    一道动态树好题。

    1. 这道题让我想了很久的是,下放同值的操作和下放增量的操作哪个先呢?
      回答:先下放同值。
      为什么?因为如果一个点被赋了同值标记,那么它的增量要归零。(覆盖了)
      所以当一个点既有同值标记,又有增量标记时,应先下放同值标记给儿子。
    2. 还有一个需要注意的是:对x~y进行处理,把那条路径取出后,应该先更新一下根的值。

    细节有点多,重点看代码.

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define g g()
    #define lc tr[x].son[0]
    #define rc tr[x].son[1]
    using namespace std;
    const int N=1e5+10,inf=1<<30,size=1<<25;
    
    char buf[size],*p1=buf,*p2=buf;
    char g{return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++;}
    void qr(int &x)
    {
    	char c=g;bool v=x=0;
    	while(!(isdigit(c)||c=='-'))c=g;
    	if(c=='-')v=1,c=g;
    	while(isdigit(c))x=x*10+c-'0',c=g;
    	if(v)x=-x;
    }
    void write(int x)
    {
    	if(x/10)write(x/10);
    	putchar(x%10+'0');
    }
    void pri(int x)
    {
    	if(x<0)putchar('-'),x=-x;
    	write(x);
    }
    
    struct node
    {
    	int f,son[2],d,c,lazy,ad,w1,c1,w2,c2;bool v;
    	//lazy为同值标记,ad为增量标记,w1为最大值,c1为最大值在子树中的出现次数,w2,c2描述次大值 
    }tr[N];
    inline void pushup(int d,int c,int x)//上传信息 
    {
    	if(d==-inf)return;
    	if(d>tr[x].w1)tr[x].w2=tr[x].w1,tr[x].c2=tr[x].c1,tr[x].w1=d,tr[x].c1=c;
    	else if(d==tr[x].w1)tr[x].c1+=c;
    	else if(d>tr[x].w2)tr[x].w2=d,tr[x].c2=c;
    	else if(d==tr[x].w2)tr[x].c2+=c;
    }
    void update(int x)//更新信息 
    {
    	tr[x].c=tr[lc].c+tr[rc].c+1;
    	tr[x].w1=tr[x].d;tr[x].c1=1;tr[x].w2=-inf;
    	if(lc)pushup(tr[lc].w1,tr[lc].c1,x),pushup(tr[lc].w2,tr[lc].c2,x);
    	if(rc)pushup(tr[rc].w1,tr[rc].c1,x),pushup(tr[rc].w2,tr[rc].c2,x);
    }
    void fz(int x)//翻转 
    {
    	tr[x].v=0;swap(lc,rc);
    	tr[lc].v^=1;tr[rc].v^=1;
    }
    void wh(int x,int y)//下放同值标记
    {
    	if(!x)return; 
    	tr[x].d=tr[x].lazy=y;
    	tr[x].w1=y;tr[x].c1=tr[x].c;
    	tr[x].w2=-inf;
    	tr[x].ad=0;//清空之前的增加标记 
    }
    void same(int x)
    {
    	wh(lc,tr[x].lazy);
    	wh(rc,tr[x].lazy);
    	tr[x].lazy=-inf;//lazy要设为无穷小,不能为0 
    }
    void add(int x,int y)//下放增量标记 
    {
    	if(!x)return;
    	tr[x].d+=y;tr[x].ad+=y;
    	tr[x].w1+=y;if(tr[x].w2!=-inf)tr[x].w2+=y;
    }
    void increase(int x)
    {
    	add(lc,tr[x].ad);
    	add(rc,tr[x].ad);
    	tr[x].ad=0;
    }
    bool rt(int x){return tr[tr[x].f].son[0]!=x&&tr[tr[x].f].son[1]!=x;}//是否为根 
    void dfs(int x)//递归维护 
    {
    	if(!rt(x))dfs(tr[x].f);
    	if(tr[x].v)fz(x);
    	if(tr[x].lazy!=-inf)same(x);
    	if(tr[x].ad!=0)increase(x);
    }
    void rotate(int x,int w)//旋转 
    {
    	int f=tr[x].f,ff=tr[f].f,r,R;
    	r=tr[x].son[w];R=f;tr[R].son[1-w]=r;if(r)tr[r].f=R;
    	r=x;R=ff;if(tr[R].son[0]==f)tr[R].son[0]=r;else if(tr[R].son[1]==f)tr[R].son[1]=r;tr[r].f=R;
    	r=f;R=x;tr[R].son[w]=r;tr[r].f=R;update(f);update(x);
    }
    void splay(int x)
    {
    	dfs(x);
    	while(!rt(x))
    	{
    		int f=tr[x].f;
    		if(rt(f))rotate(x,tr[f].son[0]==x);
    		else
    		{
    			int ff=tr[f].f,a=(tr[f].son[0]==x),b=(tr[ff].son[0]==f);
    			if(a^b)rotate(x,a),rotate(x,b);
    			else rotate(f,a),rotate(x,a);
    		}
    	}
    }
    void access(int x){for(int y=0;x;x=tr[y=x].f)splay(x),rc=y,update(x);}
    void makeroot(int x){access(x);splay(x);tr[x].v^=1;}
    void split(int x,int y){makeroot(y);access(x);splay(x);}
    void link(int x,int y){makeroot(x);tr[x].f=y;access(x);}
    void cut(int x,int y){split(x,y);lc=tr[y].f=0;update(x);}
    void query(int x,int y){
    	split(x,y);
    	if(tr[x].w2==-inf)puts("ALL SAME");
    	else pri(tr[x].w2),putchar(' '),pri(tr[x].c2),puts("");
    }
    int main()
    {
    	int T,n,m,op,x,y,d;
    	qr(T);
    	for(int kk=1;kk<=T;kk++){
    		qr(n);qr(m);					            //f,son[2],   d,  c,lazy,ad, w1,   c1,w2,c2,v;
    		for(int i=1;i<=n;i++)qr(tr[i].d),tr[i]=(node){0,{0,0},tr[i].d,1,-inf,0,tr[i].d,1,-inf,0,0};
    		for(int i=1;i<n;i++)
    			qr(x),qr(y),link(x,y);
    		printf("Case #%d:
    ",kk);
    		while(m--){ 
    			qr(op);qr(x);qr(y);
    			switch(op){
    				case 1:cut(x,y);qr(x);qr(y);link(x,y);break;
    				case 2:qr(d);split(x,y);wh(x,d);break;//先给一个点更新,使得将来上面的点能确定下面的信息 
    				case 3:qr(d);split(x,y);add(x,d);break;
    				case 4:query(x,y);break;
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    WTL介绍
    创业创意
    VelocityTracker简单介绍
    strip 命令的使用方法
    CFileDialog的使用方法简单介绍
    讨论oracle在rowid和rownum
    java entry
    24点经典算法
    char与byte差异
    蓝牙设计
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373893.html
Copyright © 2020-2023  润新知