题目链接
思路
非常好的LCT模板题。。。
乘法和加法lazy tag是可以叠加的,这个做法和线段树的lazy tag叠加是完全一样的。。。
刚开始pushdown标记很傻叉地写拙了,害得我盲调了半个多小时。。。郁闷。。。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 200000
#define MOD 51061
#define lson ch[o][0]
#define rson ch[o][1]
using namespace std;
typedef unsigned int uint;
int ch[MAXN][2],fa[MAXN],size[MAXN];
uint sum[MAXN],multag[MAXN],addtag[MAXN],val[MAXN];
int stack[MAXN],top=0;
bool rev[MAXN];
bool isRoot(int o)
{
return ch[fa[o]][0]!=o&&ch[fa[o]][1]!=o;
}
void pushup(int o)
{
sum[o]=(val[o]+sum[lson]+sum[rson])%MOD;
size[o]=(size[lson]+size[rson]+1)%MOD;
}
void cal(int o,uint mulv,uint addv) //子树o对应区间先乘上mulv后加上addv
{
if(!o) return;
val[o]=((val[o]*mulv)%MOD+addv)%MOD;
sum[o]=((sum[o]*mulv)%MOD+addv*size[o]%MOD)%MOD;
addtag[o]=(addtag[o]*mulv+addv)%MOD; //!!!!!!
multag[o]=(multag[o]*mulv)%MOD;
}
void pushdown(int o)
{
if(rev[o])
{
rev[lson]^=1;
rev[rson]^=1;
swap(lson,rson);
rev[o]=false;
}
if(multag[o]!=1||addtag[o]!=0) cal(lson,multag[o],addtag[o]),cal(rson,multag[o],addtag[o]); //!!!!!!!!!!
multag[o]=1,addtag[o]=0;
}
void rot(int x)
{
int y=fa[x],z=fa[y];
int p,q;
if(ch[y][0]==x) p=0;
else p=1;
q=p^1;
if(!isRoot(y))
{
if(ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
fa[x]=z,fa[y]=x;
ch[y][p]=ch[x][q];
fa[ch[x][q]]=y;
ch[x][q]=y;
pushup(y);
pushup(x);
}
void splay(int x)
{
top=0;
stack[++top]=x;
for(int i=x;!isRoot(i);i=fa[i]) stack[++top]=fa[i];
for(int i=top;i>=1;i--) pushdown(stack[i]);
while(!isRoot(x))
{
int y=fa[x],z=fa[y];
if(!isRoot(y))
{
if((ch[y][0]==x)==(ch[z][0]==y)) rot(y);
else rot(x);
}
rot(x);
}
}
void access(int x) //打通x到根节点的关键路径
{
int tmp=0;
while(x)
{
splay(x);
ch[x][1]=tmp;
pushup(x); //!!!!!!
tmp=x;
x=fa[x];
}
}
void makeroot(int x) //使x成为根节点
{
access(x);
splay(x);
rev[x]^=1;
}
void link(int x,int y) //连接x,y,y是x的父亲
{
makeroot(x);
fa[x]=y;
}
void cut(int x,int y) //断开x,y,y是x父亲
{
makeroot(x);
access(y);
splay(y);
ch[y][0]=fa[x]=0;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
link(u,v);
}
for(int i=1;i<=n;i++)
val[i]=sum[i]=multag[i]=size[i]=1;
for(int i=1;i<=m;i++)
{
char cmd[10];
int x,y,addv,mulv;
scanf("%s%d%d",cmd,&x,&y);
if(cmd[0]=='+') //x到y路径加
{
scanf("%d",&addv);
makeroot(x);
access(y);
splay(y);
cal(y,1,addv);
}
else if(cmd[0]=='-') //cut and link
{
cut(x,y);
scanf("%d%d",&x,&y);
link(x,y);
}
else if(cmd[0]=='*') //路径乘法
{
scanf("%d",&mulv);
makeroot(x);
access(y);
splay(y);
cal(y,mulv,0);
}
else if(cmd[0]=='/') //路径和
{
makeroot(x);
access(y);
splay(y);
printf("%d\n",sum[y]);
}
}
return 0;
}