题目

https://www.luogu.com.cn/problem/P1501
一棵 nn 个点的树,每个点的初始权值为 11。
对于这棵树有 qq 个操作,每个操作为以下四种操作之一:

  • u v c:将 uu 到 vv 的路径上的点的权值都加上自然数 cc;
  • u1 v1 u2 v2:将树中原有的边 (u_1,v_1)(u
    1

    ,v
    1

    ) 删除,加入一条新边 (u_2,v_2)(u
    2

    ,v
    2

    ),保证操作完之后仍然是一棵树;
  • u v c:将 uu 到 vv 的路径上的点的权值都乘上自然数 cc;

/ u v:询问 uu 到 vv 的路径上的点的权值和,将答案对 51061 取模。

思路

LCT练习题,结果我调了一个晚上+一个中午……
然后发现是pushdown打错了
这里我说一下要注意的几个点:这题要维护两个标记,更新乘法标记时要同时更新加法标记
还有要开long long!!

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+77,mod=51061;
int ch[N][2],fa[N],rev[N],Q[N],top,n,q;
ll _add[N],_mul[N],sum[N],siz[N],a[N];
bool isroot(int x)
{
	return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
bool get(int x)
{
	return ch[fa[x]][1]==x;
}
void mul(int x,ll c)
{
	sum[x]*=c; sum[x]%=mod;
	a[x]*=c; a[x]%=mod;
	_mul[x]*=c; _mul[x]%=mod;
	_add[x]*=c; _add[x]%=mod;
}
void add(int x,ll c)
{
	sum[x]+=c*(ll)siz[x]; sum[x]%=mod;
	a[x]+=c; a[x]%=mod;
	_add[x]+=c; _add[x]%=mod;
}
void pushdown(int x)
{
	if(rev[x])
	{
		rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
		swap(ch[x][0],ch[x][1]);
		rev[x]=0;
	}
	if(_mul[x]!=1)
	{
		if(ch[x][0]) mul(ch[x][0],_mul[x]);
		if(ch[x][1]) mul(ch[x][1],_mul[x]);
		_mul[x]=1;
	}
	if(_add[x])
	{
		if(ch[x][0]) add(ch[x][0],_add[x]);
		if(ch[x][1]) add(ch[x][1],_add[x]);
		_add[x]=0;
	}
}
void update(int x)
{
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
	sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+a[x])%mod;
}
void rotate(int x)
{
	int y=fa[x],z=fa[y],l=get(x),r=l^1;
	if(!isroot(y)) ch[z][get(y)]=x;
	fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y;
	update(x); update(y);
}
void splay(int x)
{
	top=0;
	Q[++top]=x;
	for(int i=x; !isroot(i); i=fa[i]) 
		Q[++top]=fa[i];
	while(top) pushdown(Q[top--]);
	while(!isroot(x))
	{
		int y=fa[x],z=fa[y],d1=ch[y][1]==x,d2=ch[z][1]==y;
		if(!isroot(y))
		{
			if(d1==d2) rotate(y),rotate(x); else rotate(x),rotate(x);
		}
		else rotate(x);
	}
	update(x);
}
void add(int x,int c)
{
	_add[x]=(_add[x]+c)%mod; sum[x]=(sum[x]+siz[x]*c)%mod; a[x]=(a[x]+c)%mod;
}
void mul(int x,int c)
{
	_add[x]=_add[x]*c%mod; _mul[x]=_mul[x]*c%mod; sum[x]=sum[x]*c%mod; a[x]=(a[x]*c)%mod;
}
void access(int x)
{
	for(int t=0; x; t=x,x=fa[x])
	{
		splay(x),ch[x][1]=t;
		update(x);
		if(t) fa[t]=x;
	}
}
void makeroot(int x)
{
	access(x); 
	splay(x); 
	rev[x]^=1;
}
void link(int x,int y)
{
	makeroot(x); fa[x]=y;
}
void cut(int x,int y)
{
	makeroot(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y);
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1; i<=n; i++) siz[i]=1,_mul[i]=1,a[i]=1;
	for(int i=1,x,y; i<n; i++)
	{
		scanf("%d%d",&x,&y); link(x,y);
	}
	while(q--)
	{
		char op='$';
		while(op!='+'&&op!='-'&&op!='*'&&op!='/') op=getchar();
		if(op=='+')
		{
			int x,y,c;
			scanf("%d%d%d",&x,&y,&c);
			makeroot(x); access(y); splay(y); add(y,c);
		}
		else if(op=='-')
		{
			int x1,y1,x2,y2;
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2); cut(x1,y1); link(x2,y2);
		}
		else if(op=='*')
		{
			int x,y,c;
			scanf("%d%d%d",&x,&y,&c);
			makeroot(x); access(y); splay(y); mul(y,c);
		}
		else if(op=='/')
		{
			int x,y;
			scanf("%d%d",&x,&y); 
			makeroot(x); 
			access(y); splay(y);
			printf("%lld\n",sum[y]);
		}
	}
}