BZOJ 2631:tree
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
Solution
比较裸的lct+维护splaysum+设tag
tag比较恶心。。调了好久。。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 1000001
#define mod 51061
struct splay{
int ch[2],pf,fa,size;
unsigned int sum,tag,ctag,v;
bool rev;
}t[maxn];
void update(int poi)
{
int l=t[poi].ch[0],r=t[poi].ch[1];
t[poi].sum=(t[l].sum+t[r].sum+t[poi].v)%mod;
t[poi].size=t[l].size+t[r].size+1;
}
void work1(unsigned int poi,unsigned int ctt)
{
t[poi].tag=t[poi].tag*ctt%mod;
t[poi].sum=t[poi].sum*ctt%mod;
t[poi].v=t[poi].v*ctt%mod;
}
void work2(unsigned int poi,unsigned int ctt)
{
t[poi].sum=(t[poi].sum+t[poi].size*ctt)%mod;
t[poi].v=(t[poi].v+ctt)%mod;
}
void pushdown(int poi)
{
int l=t[poi].ch[0],r=t[poi].ch[1];
if(t[poi].rev)
{
t[t[poi].ch[0]].rev^=1;
t[t[poi].ch[1]].rev^=1;
swap(t[poi].ch[0],t[poi].ch[1]);
t[poi].rev=0;
}
if(t[poi].ctag!=1)
{
t[l].ctag=t[l].ctag*t[poi].ctag%mod;
t[r].ctag=t[r].ctag*t[poi].ctag%mod;
work1(l,t[poi].ctag);
work1(r,t[poi].ctag);
t[poi].ctag=1;
}
if(t[poi].tag)
{
t[l].tag=(t[l].tag+t[poi].tag)%mod;
t[r].tag=(t[r].tag+t[poi].tag)%mod;
work2(l,t[poi].tag);
work2(r,t[poi].tag);
t[poi].tag=0;
}
}
inline int in()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
return x;
}
struct edge{
int to,lst;
}e[maxn*2];
int last[maxn],tot,stack[maxn],top=0,g[maxn];
void add(int u,int v)
{
e[++tot]=(edge){v,last[u]};last[u]=tot;
e[++tot]=(edge){u,last[v]};last[v]=tot;
}
void bfs(int poi,int lst)
{
g[poi]=1;
t[poi].size=1;
if(lst)t[poi].pf=lst;
for(int i=last[poi];i;i=e[i].lst)
if(!g[e[i].to])
bfs(e[i].to,poi);
}
void rotate(int &x,int d)
{
int y=t[x].fa,z=t[y].fa;t[x].pf=0;
if(z){if(t[z].ch[0]==y)t[z].ch[0]=x;else t[z].ch[1]=x;}
else t[x].pf=t[y].pf;
t[y].pf=0;t[t[x].ch[d]].pf=0;
t[y].fa=x,t[t[x].ch[d]].fa=y,t[x].fa=z;
t[y].ch[d^1]=t[x].ch[d];t[x].ch[d]=y;
update(y);update(x);
}
void splay(int &x)
{
int y,z;
for(int i=x;i;i=t[i].fa)stack[++top]=i;
for(;top;top--)pushdown(stack[top]);
while(t[x].fa)
{
y=t[x].fa;z=t[y].fa;
if(z)
{
if(t[z].ch[0]==y&&t[y].ch[0]==x)rotate(y,1);
else if(t[z].ch[1]==y&&t[y].ch[1]==x)rotate(y,0);
else if(t[z].ch[1]==y&&t[y].ch[0]==x)rotate(x,1);
else if(t[z].ch[0]==y&&t[y].ch[1]==x)rotate(x,0);
}
if(t[t[x].fa].ch[0]==x)rotate(x,1);
else rotate(x,0);
}
}
void access(int x)
{
splay(x);
t[t[x].ch[1]].pf=x,t[t[x].ch[1]].fa=0;t[x].ch[1]=0;
update(x);
while(t[x].pf)
{
int y=t[x].pf;
splay(y);
t[t[y].ch[1]].pf=y,t[t[y].ch[1]].fa=0;
t[x].pf=0;t[x].fa=y;t[y].ch[1]=x;
update(y);x=y;
}
}
void beroot(int x)
{
access(x);
splay(x);
t[x].rev^=1;
}
void cut(int y,int x)
{
beroot(x);access(y);
splay(y);t[y].ch[0]=0;
t[x].fa=t[x].pf=0;
update(y);
}
void link(int y,int x)
{
beroot(x),access(y);
t[x].fa=y;
}
int main()
{
freopen("2631.in","r",stdin);
freopen("2631.out","w",stdout);
int n,m;
n=in(),m=in();
for(int i=1;i<n;i++)
{
int u=in(),v=in();
add(u,v);
}
for(int i=1;i<=n;i++)t[i].size=t[i].v=t[i].ctag=1;
bfs(1,0);
for(int i=1;i<=m;i++)
{
char ch;
int u,v,c,C;
scanf("\n%c",&ch);
if(ch=='*')
{
v=in(),u=in(),c=in();
beroot(u);access(v);
splay(v);
t[v].ctag=t[v].ctag*c%mod;
t[v].v=t[v].v*c%mod;
t[v].sum=t[v].sum*c%mod;
t[v].tag=t[v].tag*c%mod;
}
else if(ch=='-')
{
u=in(),v=in();c=in();C=in();
cut(u,v);link(c,C);
}
else if(ch=='+')
{
v=in(),u=in(),c=in();
beroot(u);access(v);
splay(v);t[v].tag=(c+t[u].tag)%mod;
t[v].sum=(t[v].sum+t[v].size*c)%mod;
t[v].v=(t[v].v+c)%mod;
}
else
{
u=in(),v=in();
beroot(u);
access(v);
splay(v);
printf("%d\n",t[v].sum%mod);
}
}
}

2797

被折叠的 条评论
为什么被折叠?



