【题目描述】
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-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
Sample Input
1 2
2 3
* 1 3 4
/ 1 1
Sample Output
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,跑的挺快的。