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 21 2
2 3
* 1 3 4
/ 1 1
Sample Output
4HINT
数据规模和约定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]); } } }
相关文章推荐
- JavaScript 操作 Cookie
- squid搭建
- Bitmap二次采样以及压缩另一种方式
- Linux网络相关命令小结
- 路是自己选的,这是一种生的宿命
- NSDate和NSDateFormatter
- iOS 学习(Whereami)
- 用闭包实现含有定时器的tab栏的切换与函数封装
- 学习远控界面设计一: 程序界面大小
- samba搭建
- 重装系统后必装软件
- java中的this关键字
- 每天一个Linux之locate命令
- map中使用自定义类指针作为key
- WIN32服务程序(二):卸载服务
- dns搭建
- java socket 编程
- Android Studio安装、配置
- Linux下rsync增加SSH端口号的用法
- JavaScript(1)