2631: tree
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 3372 Solved: 1135
[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-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
解題思路:link cut tree模板,市賽打擊後的第一題,加油吧。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,qg,len;
const int maxn=51061;
int to[300000],next[300000],h[300000];
unsigned int fa[110000],l[110000],r[110000],rever[110000],size[110000];
unsigned int zhi[110000],sum[110000],add[110000],mul[110000];
int q[110000];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0'||y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void insert(int x,int y)
{
++len; to[len]=y; next[len]=h[x]; h[x]=len;
}
void dfs(int now,int f)
{
fa[now]=f; l[now]=r[now]=add[now]=rever[now]=0; sum[now]=zhi[now]=mul[now]=1; size[now]=1;
int u=h[now];
while (u!=0)
{
if (to[u]!=f)
{
dfs(to[u],now);
}
u=next[u];
}
}
void pushdown(int now)
{
if (rever[now])
{
rever[l[now]]^=1; rever[r[now]]^=1;
rever[now]^=1; swap(l[now],r[now]);
}
if (mul[now]!=1)
{
if (l[now])mul[l[now]]=mul[l[now]]*mul[now]%maxn,zhi[l[now]]=zhi[l[now]]*mul[now]%maxn,sum[l[now]]=sum[l[now]]*mul[now]%maxn,add[l[now]]=add[l[now]]*mul[now]%maxn;
if (r[now])mul[r[now]]=mul[r[now]]*mul[now]%maxn,zhi[r[now]]=zhi[r[now]]*mul[now]%maxn,sum[r[now]]=sum[r[now]]*mul[now]%maxn,add[r[now]]=add[r[now]]*mul[now]%maxn;
mul[now]=1;
}
if (add[now]!=0)
{
if (l[now])add[l[now]]=(add[l[now]]+add[now])%maxn,zhi[l[now]]=(zhi[l[now]]+add[now])%maxn,sum[l[now]]=(sum[l[now]]+add[now]*size[l[now]]%maxn)%maxn;
if (r[now])add[r[now]]=(add[r[now]]+add[now])%maxn,zhi[r[now]]=(zhi[r[now]]+add[now])%maxn,sum[r[now]]=(sum[r[now]]+add[now]*size[r[now]]%maxn)%maxn;
add[now]=0;
}
}
void maindown(int now)
{
sum[now]=(sum[l[now]]+sum[r[now]]+zhi[now])%maxn;
size[now]=size[l[now]]+size[r[now]]+1;
}
bool isroot(int now)
{
if (l[fa[now]]==now || r[fa[now]]==now) return false;else return true;
}
void rotate(int x)
{
int y=fa[x]; int z=fa[y];
if (!isroot(y))
{
if (l[z]==y) l[z]=x; else r[z]=x;
}
fa[x]=z; fa[y]=x;
if (l[y]==x)
{
fa[r[x]]=y; l[y]=r[x]; r[x]=y;
}else
{
fa[l[x]]=y; r[y]=l[x]; l[x]=y;
}
maindown(y); maindown(x);
}
void splay(int x)
{
int now=x; int tail=1; q[tail]=x;
while (!isroot(now)) {++tail; q[tail]=fa[now]; now=fa[now];}
for (int i=tail;i>=1;--i) pushdown(q[i]);
while (!isroot(x))
{
int y=fa[x]; int z=fa[y];
if (!isroot(y))
{
if (l[z]==y ^ l[y]==x) rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int now)
{
splay(now);
while (fa[now]!=0)
{
splay(fa[now]); r[fa[now]]=now;
r[now]=0; maindown(now);
maindown(fa[now]);
splay(now);
}
splay(now); r[now]=0; maindown(now);
}
void makeroot(int now)
{
access(now); splay(now); rever[now]^=1;
}
int main()
{
n=read(); qg=read();
for (int i=1;i<=n-1;++i)
{
int u,v; u=read(); v=read();
insert(u,v); insert(v,u);
}
dfs(1,0);
for (int y=1;y<=qg;++y)
{
char c[10];
scanf("%s",c);
if (c[0]=='*')
{
int u,v,c; u=read(); v=read(); c=read();
c=c%maxn;
makeroot(u); access(v); splay(u); zhi[u]=zhi[u]*c%maxn; sum[u]=sum[u]*c%maxn; mul[u]=mul[u]*c%maxn; add[u]=add[u]*c%maxn;
}else
if (c[0]=='-')
{
int u1,v1,u2,v2;
u1=read(); v1=read(); u2=read(); v2=read();
makeroot(u1); access(v1); splay(u1); r[u1]=0; fa[v1]=0; maindown(u1);
access(u2); makeroot(v2); splay(u2); fa[v2]=u2;
}else
if (c[0]=='/')
{
int u,v; u=read(); v=read();
makeroot(u);
access(v);
splay(u); printf("%d\n",sum[u]%maxn);
}else
if (c[0]=='+')
{
int u,v,c; u=read(); v=read(); c=read();
c=c%maxn;
makeroot(u);
access(v); splay(u);
zhi[u]=(zhi[u]+c)%maxn; sum[u]=(sum[u]+size[u]*c%maxn)%maxn; add[u]=(add[u]+c)%maxn;
}
}
}