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行,每行描述一个操作
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
对于每个/对应的答案输出一行
Sample Input
3 2
1 2
2 3
* 1 3 4
/ 1 1
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;
}