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;
}
原文地址:https://www.cnblogs.com/zsyzlzy/p/12373893.html