bzoj 2631(link cut tree)

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 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,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



解題思路: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;
}
}
 
}

發佈了149 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章