[bzoj2631]tree Link-Cut-Tree

2631: tree

Time Limit: 30 Sec   Memory Limit: 128 MB
[ Submit][ Status][ Discuss]

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


Source

a:add 
m:multiply
LCT操作基本集齐,黄学长的模板虽然简洁,但是速度不够,然而我也不知道如何优化这个的常数,蒟蒻觉得已经够优了(读优都没加)
总结一下:
LCT真是个神奇的东西
LCT有点慢啊,或许有点暴力
change:断掉两个点
move_to_root:转到根节点
link:相连
cut:剪边
access:使到根节点整为prefer edge
#include<iostream>
#include<cstdio>
#define mod 51061
using namespace std;
const int N = 100005;
typedef unsigned int ll;
ll af[N],mf[N],sum[N],va[N];
int c[N][2],fa[N],siz[N],sta[N],top=0,n,m;
char ch[10]; bool rev[N];
bool isroot( int x ){
	return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
void modify( int x, int m, int a ){
	if( !x ) return ;
	va[x] = (va[x]*m+a)%mod;
	sum[x] = (sum[x]*m+a*siz[x])%mod;
	af[x] = (af[x]*m+a)%mod;
	mf[x] = (mf[x]*m)%mod;
}
void update( int x ){
	sum[x] = (sum[c[x][1]] + sum[c[x][0]] + va[x])%mod;
	siz[x] = (siz[c[x][1]] + siz[c[x][0]] + 1)%mod;
}
void pushdown( int x ){
	if( rev[x] ){
		rev[c[x][0]] ^= 1; rev[c[x][1]] ^= 1; rev[x] = 0;
		swap(c[x][0],c[x][1]);
	}
	if( mf[x] != 1 || af[x] != 0 )
		modify(c[x][0],mf[x],af[x]), modify(c[x][1],mf[x],af[x]);
	mf[x] = 1; af[x] = 0;
}
void rotate( int x ){
	int y = fa[x], z = fa[y], l, r;
	l = (c[y][1] == x); r = l^1;
	if(!isroot(y)) c[z][y==c[z][1]] = x;
	fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
	c[y][l] = c[x][r]; c[x][r] = y;
	update(y); update(x);
}
void splay( int x ){
	sta[++top] = x;
	for( int i = x; !isroot(i); i = fa[i] ) sta[++top] = fa[i];
	while( top ) pushdown(sta[top--]);
	while( !isroot(x) ){
		int y = fa[x], z = fa[y];
		if( !isroot(y) ){
			if( (c[y][0]==x)^(c[z][0]==y) ) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
void access( int x ){
	for( int now = 0; x; now = x, x = fa[x] ){
		splay(x); c[x][1] = now; update(x);
	}
}
void move_to_root( int x ){
	access(x); splay(x); rev[x] ^= 1;
}
void change( int x, int y ){
	move_to_root(y); access(x); splay(x);
}
void link( int x, int y ){
	move_to_root(x); fa[x] = y;
}
void cut( int x, int y ){
	move_to_root(x); access(y); splay(y); fa[x] = c[y][0] = 0;
}
int main(){
	scanf("%d%d", &n, &m);
	for( int i = 1; i <= n; i++ ) sum[i] = siz[i] = va[i] = mf[i] = 1;
	for( int i = 1,u,v; i < n; i++ ) scanf("%d%d", &u, &v), link(u,v);
	for( int i = 1,u,v,c; i <= m; i++ ){
		scanf("%s", ch); scanf("%d%d", &u, &v);
		if( ch[0] == '+' ){
			scanf("%d", &c);
			change( u, v ); modify( u, 1, c );
		} if( ch[0] == '-' ){
			cut( u, v );
			scanf("%d%d", &u, &v);
			link( u, v );
		} if( ch[0] == '*' ){
			scanf("%d", &c);
			change( u, v ); modify( u, c, 0 );
		} if( ch[0] == '/' ){
			change( u, v );
			printf("%d\n", sum[u]);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值