您的位置:首页 > 其它

BZOJ 2631 TREE

2016-01-01 15:42 369 查看

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

      这题是LCT的模板题,其余没什么好讲的,SUM为路径的权值和,A为点权,这题我在标记上耗了很久,我们记录CHEN 和JIA,假定Y和Z分别作为加和乘的标记,那么CHEN*=Z,JIA=JIA*Z+Y,注意这时候SUM为SUM*Z+SIZE*Y,还有这题用UNSIGNED INT 会快很多,我从30000ms跑到了16800ms......

废话不说附上代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXX=100100;
int fa[MAXX],lc[MAXX],rc[MAXX],m;
unsigned int sum[MAXX],jia[MAXX],chen[MAXX],a[MAXX];
int n,i,j,k,x,y,z,ans,tot,cnt[MAXX],tag[MAXX],size[MAXX];
char s[15];
inline int get()
{
char c;
while ((c=getchar())<48||c>57);
int res=c-'0';
while ((c=getchar())>=48&&c<=57)
res=res*10+c-'0';
return res;
}
inline int isroot(int x)
{
return ((lc[fa[x]]==x)||(rc[fa[x]]==x));
}
inline void rev(int x)
{
swap(lc[x],rc[x]);
cnt[x]^=1;
}
inline void putdown1(int x,unsigned int y,unsigned int z)
{
jia[x]=jia[x]*z+y;
jia[x]%=51061;
chen[x]*=z;
chen[x]%=51061;
a[x]=a[x]*z+y;
a[x]%=51061;
sum[x]=sum[x]*z+y*size[x];
sum[x]%=51061;
}
inline void putdown(int x)
{
if (cnt[x])
{
cnt[x]^=1;
if (lc[x]) rev(lc[x]);
if (rc[x]) rev(rc[x]);
}
if (jia[x]||chen[x]!=1)
{
if (lc[x]) putdown1(lc[x],jia[x],chen[x]);
if (rc[x]) putdown1(rc[x],jia[x],chen[x]);
jia[x]=0;chen[x]=1;
}
}
inline void pushup(int x)
{
sum[x]=sum[lc[x]]+sum[rc[x]]+a[x];
sum[x]%=51061;
size[x]=size[lc[x]]+size[rc[x]]+1;
}
inline void turn(int x)
{
int y=fa[x],z=fa[y],b=0;
if (lc[y]==x) b=rc[x];
else b=lc[x];
if (b) fa[b]=y;
fa[x]=z;fa[y]=x;
if (z)
if (lc[z]==y) lc[z]=x;
else if (rc[z]==y) rc[z]=x;
if (lc[y]==x) rc[x]=y,lc[y]=b;
else lc[x]=y,rc[y]=b;
pushup(y);
}
inline void splay(int x)
{
int i,len=0;
for(i=x;isroot(i);i=fa[i])
tag[++len]=i;
tag[++len]=i;
while (len) putdown(tag[len--]);
while (isroot(x))
{
int y=fa[x];
if (isroot(y))
if ((lc[y]==x)==(lc[fa[y]]==y)) turn(y);
else turn(x);
turn(x);
}
pushup(x);
}
inline void access(int x)
{
int sb=0;
while (x)
{
splay(x);
rc[x]=sb;
sb=x;
x=fa[x];
}
}
inline void makeroot(int x)
{
access(x);
splay(x);
rev(x);
}
inline void LINK(int x,int y)
{
makeroot(x);
fa[x]=y;
}
inline void cut(int x,int y)
{
access(x);splay(y);
if (fa[y]==x)
fa[y]=0;
else{
access(y);
splay(x);
fa[x]=0;
}
}
inline void change(int x,int y)
{
makeroot(y);
access(x);
splay(x);
}
int main()
{
n=get();m=get();
a
=chen
=1;
for(i=1;i<n;i++)
{
a[i]=1;
chen[i]=1;
x=get();y=get();
LINK(x,y);
}
for(i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='-')
{
x=get();y=get();
cut(x,y);
x=get();y=get();
LINK(x,y);
}
else if (s[0]=='+')
{
x=get();y=get();z=get();
change(x,y);
putdown1(x,(unsigned int)z,1);
}
else if (s[0]=='*')
{
x=get();y=get();z=get();
change(x,y);
putdown1(x,0,(unsigned int)z);
}
else{
x=get();y=get();
change(x,y);
printf("%u\n",sum[x]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: