BZOJ_2631_tree_LCT
BZOJ_2631_tree_LCT
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行,每行描述一个操作
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
对于每个/对应的答案输出一行
Sample Input
3 2
1 2
2 3
* 1 3 4
/ 1 1
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模板题。注意乘法和加法下传的顺序。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 100050 #define mod 51061 #define ls ch[p][0] #define rs ch[p][1] #define get(x) (ch[f[x]][1]==x) typedef unsigned int ui; int n,m,ch[N][2],f[N],rev[N]; ui sum[N],mul[N],add[N],siz[N],val[N]; char opt[10]; inline bool isrt( int x) { return ch[f[x]][0]!=x&&ch[f[x]][1]!=x; } void pushdown( int p) { if (mul[p]!=1) { ui u=mul[p]; sum[ls]=sum[ls]*u%mod; mul[ls]=mul[ls]*u%mod; add[ls]=add[ls]*u%mod; val[ls]=val[ls]*u%mod; sum[rs]=sum[rs]*u%mod; mul[rs]=mul[rs]*u%mod; add[rs]=add[rs]*u%mod; val[rs]=val[rs]*u%mod; mul[p]=1; } if (add[p]) { ui d=add[p]; sum[ls]=(sum[ls]+siz[ls]*d%mod)%mod; add[ls]=(add[ls]+d)%mod; val[ls]=(val[ls]+d)%mod; sum[rs]=(sum[rs]+siz[rs]*d%mod)%mod; add[rs]=(add[rs]+d)%mod; val[rs]=(val[rs]+d)%mod; add[p]=0; } if (rev[p]) { swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]); rev[ls]^=1; rev[rs]^=1; rev[p]=0; } /*cal(ls , add[p] , mul[p] , rev[p]); cal(rs , add[p] , mul[p] , rev[p]); add[p] = rev[p] = 0 , mul[p] = 1;*/ } void pushup( int p) { siz[p]=siz[ls]+siz[rs]+1; sum[p]=(sum[ls]+sum[rs]+val[p])%mod; } void update( int p) { if (!isrt(p)) update(f[p]); pushdown(p); } void rotate( int x) { int y=f[x],z=f[y],k=get(x); if (!isrt(y)) ch[z][ch[z][1]==y]=x; ch[y][k]=ch[x][!k]; f[ch[y][k]]=y; ch[x][!k]=y; f[y]=x; f[x]=z; pushup(y); pushup(x); } void splay( int x) { update(x); for ( int fa;fa=f[x],!isrt(x);rotate(x)) if (!isrt(fa)) rotate(get(fa)==get(x)?fa:x); } void access( int p) { int t=0; while (p) splay(p),rs=t,pushup(p),t=p,p=f[p]; } void makeroot( int p) { access(p); splay(p); swap(ls,rs); rev[p]^=1; } void link( int x, int p) { makeroot(x); f[x]=p; } void cut( int x, int p) { makeroot(x); access(p); splay(p); ls=f[x]=0; } void split( int x, int p) { makeroot(x); access(p); splay(p); } int main() { scanf ( "%d%d" ,&n,&m); int i,x,y,z,w; for (i=1;i<=n;i++) val[i]=mul[i]=siz[i]=sum[i]=1; for (i=1;i<n;i++) { scanf ( "%d%d" ,&x,&y); link(x,y); } for (i=1;i<=m;i++) { scanf ( "%s%d%d" ,opt,&x,&y); int p=y; if (opt[0]== '+' ) { scanf ( "%d" ,&z); split(x,p); sum[p]=(sum[p]+siz[p]*z%mod)%mod; val[p]=(val[p]+z)%mod; add[p]=(add[p]+z)%mod; //cal(p,z,1,0); } else if (opt[0]== '-' ) { scanf ( "%d%d" ,&z,&w); cut(x,y); link(z,w); } else if (opt[0]== '*' ) { scanf ( "%d" ,&z); split(x,p); sum[p]=sum[p]*z%mod; val[p]=val[p]*z%mod; add[p]=add[p]*z%mod; mul[p]=mul[p]*z%mod; //cal(p,0,z,0); } else { split(x,p); printf ( "%u\n" ,sum[p]); } } } |
标签:
LCT
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!