[bzoj2631]tree【LCT】

【题目描述】

Description

 一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c:将u到v的路径上的点的权值都加上自然数c;
- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
* u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

Input

  第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作

Output

  对于每个/对应的答案输出一行

Sample Input

3 2
1 2
2 3
* 1 3 4
/ 1 1

Sample Output

4


HINT

数据规模和约定

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4


【题解】

 LCT模板题,讲一下LCT基本操作(对lct一无所知的请看https://www.cnblogs.com/BLADEVIL/p/3510997.html)

1.access(x):LCT核心操作,将x到root的所有边设为偏爱边,断开其他与这条莲相邻的偏爱边

2.makeroot(x) :将x变为根

3.getroad(u,v) :(我YY的)将u设为根并将v转到u所在splay的根上(进行access操作),此时v没有右子树,左子树即要查询的链。

4.link(u,v):添加u与v的边

5.cut(u,v):删去u与v的边

6.isroot(x):判断x是否为当前splay的根,如果是,那么fa[x]的左右儿子都因没有x

实现见代码:

/* --------------
    user Vanisher
    problem bzoj-2631 LCT
----------------*/
# include <bits/stdc++.h>
# define 	ll 		long long
# define 	ui 		unsigned int
# define 	N 		100010
# define 	P 		51061
using namespace std;
ui read(){
	ui tmp=0, fh=1; char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
	return tmp*fh;
}
struct lct{
	ui pl,pr,size,tag,tag0,tag1,sum,num,fa;
}T[N];
ui st[N],n,q;
void pushtag(ui x){
	if (x==0) return;
	if (T[x].tag==1){
		T[T[x].pl].tag^=1; T[T[x].pr].tag^=1; T[x].tag^=1;
		swap(T[x].pl,T[x].pr);
	}
	if (T[x].tag1!=1){
		ui num=T[x].tag1;
		T[T[x].pl].tag0=(T[T[x].pl].tag0*num)%P; T[T[x].pl].tag1=(T[T[x].pl].tag1*num)%P;
		T[T[x].pr].tag0=(T[T[x].pr].tag0*num)%P; T[T[x].pr].tag1=(T[T[x].pr].tag1*num)%P;
		T[x].num=(T[x].num*T[x].tag1)%P; T[x].sum=(T[x].sum*T[x].tag1)%P;
		T[x].tag1=1;
	}
	if (T[x].tag0!=0){
		ui num=T[x].tag0;
		T[T[x].pl].tag0=(T[T[x].pl].tag0+num)%P; T[T[x].pr].tag0=(T[T[x].pr].tag0+num)%P;
		T[x].sum=(T[x].sum+T[x].tag0*T[x].size)%P; T[x].num=(T[x].num+T[x].tag0)%P;
		T[x].tag0=0;
	}
}
void change(ui x){
	pushtag(T[x].pl); pushtag(T[x].pr);
	T[x].sum=(T[x].num+T[T[x].pl].sum+T[T[x].pr].sum)%P;
	T[x].size=1+T[T[x].pl].size+T[T[x].pr].size;
}
bool isroot(ui x){
	return T[T[x].fa].pl!=x&&T[T[x].fa].pr!=x;
}
void zig(ui x){
	ui y=T[x].fa;
	if (!isroot(y)){
		if (T[T[y].fa].pl==y) T[T[y].fa].pl=x; else T[T[y].fa].pr=x;
	}
	T[x].fa=T[y].fa;
	T[y].pl=T[x].pr; T[T[x].pr].fa=y;
	T[y].fa=x; T[x].pr=y;
	change(y); change(x);
}
void zag(ui x){
	ui y=T[x].fa;
	if (!isroot(y)){
		if (T[T[y].fa].pl==y) T[T[y].fa].pl=x; else T[T[y].fa].pr=x;
	}
	T[x].fa=T[y].fa;
	T[y].pr=T[x].pl; T[T[x].pl].fa=y;
	T[y].fa=x; T[x].pl=y;
	change(y); change(x);
}
void splay(ui x){
	ui y=x,top=0; st[++top]=x;
	while (!isroot(y)) st[++top]=y=T[y].fa;
	for (ui i=top; i>=1; i--) pushtag(st[i]);
	while (!isroot(x)){
		y=T[x].fa;
		if (isroot(y))
			if (T[y].pl==x) zig(x); else zag(x);
			else if (T[T[y].fa].pl==y)
				if (T[y].pl==x) zig(y), zig(x);
					else zag(x), zig(x);
				else if (T[y].pl==x) zig(x), zag(x);
					else zag(y), zag(x);
	}
}
void access(ui u){
	ui v=0;
	while (u){
		splay(u);
		T[u].pr=v; T[v].fa=u;
		change(u);
		v=u;
		u=T[u].fa;
	}
}
void makeroot(ui u){
	access(u);
	splay(u);
	T[u].tag^=1;
}
void getroad(ui u, ui v){
	makeroot(u);
	access(v);
	splay(v);
}
void link(ui u, ui v){
	makeroot(u);
	T[u].fa=v;
}
void cut(ui u, ui v){
	getroad(u,v);
	T[v].pl=0; T[u].fa=0;
	change(v);
}
int main(){
	n=read(); q=read();
	for (ui i=1; i<=n; i++) 
		T[i].size=1,T[i].tag1=1,T[i].num=T[i].sum=1;
	for (ui i=1; i<n; i++)
		link(read(),read());
	char opt;
	ui u,v,c;
	for (ui i=1; i<=q; i++){
		scanf("\n%c",&opt);
		if (opt=='+'){
			u=read(), v=read(); c=read();
			getroad(u,v);
		 	T[v].tag0=(T[v].tag0+c)%P;
		}
		if (opt=='-'){
			u=read(), v=read(); cut(u,v);
			u=read(), v=read(); link(u,v);
		}
		if (opt=='*'){
			u=read(), v=read(); c=read();
			getroad(u,v);
		 	T[v].tag1=(T[v].tag1*c)%P;
		 	T[v].tag0=(T[v].tag0*c)%P;
		}
		if (opt=='/'){
			u=read(), v=read();
			getroad(u,v);
			pushtag(v); 
			printf("%d\n",T[v].sum);
		}
	}
	return 0;
}

 tips:此题要用unsigned int,跑的挺快的。


posted @ 2018-01-21 19:55  Vanisher  阅读(157)  评论(0编辑  收藏  举报