bzoj 2631: tree
Submit: 2928 Solved: 975
[Submit][Status][Discuss]
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-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
Sample Input
1 2
2 3
* 1 3 4
/ 1 1
Sample Output
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
题解:
四种操作显然要用动态树来维护,对于+和*的操作,需要打标记,但是在标记下放的时候需要考虑先放+还是先放*的问题。
假设现在树中有权值为x和权值为y的两个节点,y是x的父亲节点,要对它俩依次进行+a1 *b1 *b2 +a2这四种操作,由于y是x的父亲,所以只是对y打上标记,不会下放到x节点。x节点应该的值是:(x+a1)*b1*b2+a2=a1*b1*b2*x+a1*b1*b2+a2,令t1=a1*b1*b2 , t2=a1*b1*b2+a2,则原式可以写成:t1*x+t2 , 在这里t1即为乘法标记,t2即为加法标记,下放的方式就是 t1*x+t2的形式,从上面的式子可以看出,对于乘法标记了累计原则就是有加有乘,对于加法标记的原则是只乘不加。由此下放标记
其余的就是动态树的常规操作。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 typedef unsigned int UI; 11 const UI maxn=200000; 12 const UI mod=51061; 13 UI N,Q; 14 UI c[maxn][2],fa[maxn],key[maxn],size[maxn],sum[maxn],add[maxn],mul[maxn],st[maxn]; 15 char s[10]; 16 bool rev[maxn]; 17 bool isroot(UI x){ 18 return x!=c[fa[x]][0]&&x!=c[fa[x]][1]; 19 } 20 void calc(UI x,UI a,UI b){//节点x,进行ax+b操作 21 if(x==0) return; 22 key[x]=((key[x]*a)%mod+b)%mod; 23 sum[x]=((sum[x]*a)%mod+(b*size[x])%mod)%mod; 24 add[x]=((add[x]*a)%mod+b)%mod; 25 mul[x]=(mul[x]*a)%mod; 26 } 27 void pushup(UI x){ 28 size[x]=size[c[x][0]]+size[c[x][1]]+1; 29 sum[x]=(sum[c[x][0]]+sum[c[x][1]]+key[x])%mod; 30 } 31 void pushdown(UI x){ 32 UI l=c[x][0],r=c[x][1]; 33 if(rev[x]==true){ 34 rev[x]^=1; rev[l]^=1; rev[r]^=1; 35 swap(c[x][0],c[x][1]); 36 } 37 UI tmpa=add[x],tmpm=mul[x]; 38 add[x]=0; mul[x]=1; 39 if(tmpa!=0||tmpm!=1){ 40 calc(l,tmpm,tmpa); calc(r,tmpm,tmpa); 41 } 42 } 43 void rotate(UI x){ 44 UI y=fa[x],z=fa[y],l,r; 45 if(x==c[y][0]) l=0;else l=1; r=l^1; 46 if(!isroot(y)){ 47 if(y==c[z][0]) c[z][0]=x; 48 else c[z][1]=x; 49 } 50 fa[x]=z; fa[y]=x; fa[c[x][r]]=y; 51 c[y][l]=c[x][r]; c[x][r]=y; 52 pushup(y); pushup(x); 53 } 54 void splay(UI x){ 55 UI top=0; st[++top]=x; 56 for(UI i=x;!isroot(i);i=fa[i]){ 57 st[++top]=fa[i]; 58 } 59 for(UI i=top;i;i--) pushdown(st[i]); 60 while(!isroot(x)){ 61 UI y=fa[x],z=fa[y]; 62 if(!isroot(y)){ 63 if((x==c[y][0]&&y==c[z][0])||(x==c[y][1]&&y==c[z][1])){ 64 rotate(y),rotate(x); 65 } 66 else rotate(x),rotate(x); 67 } 68 else rotate(x); 69 } 70 } 71 void access(UI x){ 72 UI t=0; 73 while(x){ 74 splay(x); 75 c[x][1]=t; pushup(x); 76 t=x; x=fa[x]; 77 } 78 } 79 void rever(UI x){ 80 access(x); splay(x); rev[x]^=1; 81 } 82 void cut(UI x,UI y){ 83 rever(x); access(y); splay(y); c[y][0]=fa[x]=0; 84 } 85 void link(UI x,UI y){ 86 rever(x); fa[x]=y; splay(x); 87 } 88 int main(){ 89 scanf("%u%u",&N,&Q); 90 for(UI i=1;i<=N;i++) key[i]=sum[i]=size[i]=mul[i]=1; 91 for(UI i=1,u,v;i<=N-1;i++){ 92 scanf("%u%u",&u,&v); 93 link(u,v); 94 } 95 for(UI i=1;i<=Q;i++){ 96 UI u1,v1,u2,v2,cc; 97 scanf("%s",s); 98 if(s[0]=='+'){ 99 scanf("%u%u%u",&u1,&v1,&cc); 100 rever(u1); access(v1); splay(v1); 101 calc(v1,1,cc); 102 } 103 else if(s[0]=='-'){ 104 scanf("%u%u%u%u",&u1,&v1,&u2,&v2); 105 cut(u1,v1); link(u2,v2); 106 } 107 else if(s[0]=='*'){ 108 scanf("%u%u%u",&u1,&v1,&cc); 109 rever(u1); access(v1); splay(v1); 110 calc(v1,cc,0); 111 } 112 else{ 113 scanf("%u%u",&u1,&v1); 114 rever(u1); access(v1); splay(v1); 115 printf("%u\n",sum[v1]); 116 } 117 } 118 return 0; 119 }
转载于:https://www.cnblogs.com/CXCXCXC/p/5193300.html
bzoj 2631: tree相关推荐
- BZOJ 2631 tree(动态树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2631 [题目大意] 要求支持链修改,链查询,边断开,连接操作 [题解] 链修改分乘和加 ...
- bzoj 1468 Tree(点分治模板)
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1527 Solved: 818 [Submit][Status][Discus ...
- [BZOJ 2654]tree(陈立杰)
Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色 ...
- 一句话题解(20170801~20170125)
8.1 bzoj 4720 noip2016 换教室 floyd预处理+期望(薛定谔的猫) bzoj 4318 OSU! 三次函数期望值 从一次.二次推得 8.2 bzoj 1076 状压+期望DP ...
- 清北学堂学习笔记 第一期
Day 1 1.贪心的奇怪方法:调整法 调整法,顾名思义,就是用别的方式进行题目的分析以及证明,例如说luogu的最大乘积.这种题目的主要分析思路为:先考虑一些简单的情况,通过简单的情况来推出一些有用 ...
- java vi命令 退出_Git 使用vi或vim命令打开、关闭、保存文件
1 vi & vim 有两种工作模式: (1)命令模式:接受.执行 vi & vim 操作命令的模式,打开文件后的默认模式: (2)编辑模式:对打开的文件内容进行 增.删.改 操作模式 ...
- [颓废史]蒟蒻的刷题记录
QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...
- BZOJ 2588 Spoj 10628 Count on a tree | 树上主席树
BZOJ 2588 Count on a tree 题面 求树上两点之间路径上第k大的点权. 题解 一开始看到这道题觉得是树剖,然后又听说是主席树,然后以为是主席树+树剖,差点没吓死-- 然后发现,如 ...
- BZOJ.4695.最假女选手(线段树 Segment tree Beats!)
题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...
最新文章
- How to open robotium-solo-1.4.0 javadoc.jar to get the information of robotium.
- 用ipython 写spark
- TC SRM601
- linux7为nginx添加服务,CentOS7添加Nginx为系统服务
- Dos下命令运行带有包名的Java类
- c#_导出table功能
- 解密双十一小程序云背后毫秒级伸缩的Serverless计算平台:函数计算
- stm32外部中断_STM32学习笔记 | 电源管理及低功耗设计要点
- C#LeetCode刷题之#589-N叉树的前序遍历(N-ary Tree Preorder Traversal)
- 从前世今生聊一聊,大厂为啥亲睐时序数据库
- android 动画结束停留,循环动画 tween durationMillis = 90195 动画将停留在最后一针
- 我的docker随笔26:制作arm平台的python-pandas镜像
- 在Mybatis的collection标签中获取以,分隔的id字符串
- CDA考试-建模分析师-实用性大数据挖掘算法-数据挖掘概述
- looking for domain authoritative name server and domain name location
- 第二届CCF计算机职业资格认证考试题解(C++)
- Java代码如何运行的?
- 2023轻薄投影仪首选:极米Z6X Pro入手超值!
- 计算机在汽车专业中的应用,浅谈计算机技术在汽车行业中的应用.doc
- 液化气瓶监管技术如何做到正确选型
热门文章
- 网络请求中常见的加密机制和加密算法理解
- Qt:Qt使用WM_COPYDATA消息进行进程通信
- Qt:Qt使用鼠标模拟函数mouse_event和按键模拟函数keybd_even实现网页刷新功能
- 【LOJ】#2887. 「APIO2015」雅加达的摩天楼 Jakarta Skyscrapers
- oracle Instance status: READY–lsnrctl status|start|stop
- cocos2d-x多分辨率自适配及因此导致的CCListView的bug修复
- 使用 Advanced Installer 打包 一键安装Web应用程序
- JS-Demo1:JavaScript实现表格列拖动
- Preloading组件。
- 了解VS2005为你的MFC程序做的一些事