花花的森林(倍增,LCA
花花的森林,嗯,这是一篇正经的题解。
模拟考的时候没有看出来要怎么求啊,暴力地树形DP、换根、合并、求直径。居然也险险地拿到了80分,不过我们要正经地想正解。
容易想到我们可以让时光倒流,让空间扭转,离线地从最后一次操作往前,这样删边就变成加边了(合并总比拆开好做吧)
首先,我们要知道,两棵树合并后,新直径的两个端点一定是原来两棵树的两个直径的四个不同端点中的某两个(为什么?),自己画一下图,思考证明一下,这个结论并不难得出。
所以说合并时的新直径就只会有六种即 C(4,2),那么我们分别求出这六个直径的值(当然原本的两种不用求),用最大的作为新树的直径就好啦~,并且记下此时的两个端点。
那要怎么求直径啊~?
当然是倍增啦。
可是可是,我们都把树拆成一棵棵了,怎么倍增啊,合并后不是还要重新算一次倍增的数组吗?
我们可以在原树上倍增呀,没必要真的把树拆了(如果题目让你做什么你就做什么,一定会被带离正解的),在一棵树上,两点之间的简单路径是唯一的。
(那你真是个小机灵鬼~)
然后合并就用并查集维护。
哦对了,还有一个细节,从后往前做我们会遇到除法的问题(难不成你要循环一遍整个森林求一次ans吗)所以在模质数的意义下,使用费马小定理求逆元来进行除法。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 #define For(i,a,b) for(register int i=a;i<=b;++i) 8 #define Dwn(i,a,b) for(register int i=a;i>=b;--i) 9 #define Re register 10 #define Pn putchar('\n') 11 #define llg long long 12 using namespace std; 13 const int N=1e5+10,md=1e9+7; 14 llg a[N],ans=1,dt[N],pt[N][2],fn[N]; 15 int head[N],nxt[N*2],v[N*2],cnt=1; 16 int pa[N],sz[N],n,m,x,y,Q[N]; 17 int f[N][25]; 18 llg d[N][25]; 19 struct EDG{ 20 int a,b; 21 }ed[N]; 22 inline void read(int &v){ 23 v=0; 24 char c=getchar(); 25 while(c<'0'||c>'9')c=getchar(); 26 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar(); 27 } 28 inline void read(llg &v){ 29 v=0; 30 char c=getchar(); 31 while(c<'0'||c>'9')c=getchar(); 32 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar(); 33 } 34 void write(llg x){ 35 if(x>9)write(x/10); 36 int xx=x%10; 37 putchar(xx+'0'); 38 } 39 int find(int x){ 40 int r=x; 41 while(pa[r]!=r)r=pa[r]; 42 int i,j; 43 i=x; 44 while(pa[i]!=r){ 45 j=pa[i]; pa[i]=r; i=j; 46 } 47 return r; 48 } 49 void add(int ux,int vx){ 50 cnt++; 51 nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; 52 cnt++; 53 nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; 54 } 55 llg Qsm(llg x,int k){ 56 llg ans=1; 57 while(k){ 58 if(k&1)ans=(ans*x)%md; 59 x=(x*x)%md; 60 k>>=1; 61 } 62 return ans; 63 } 64 65 int dep[N]; 66 void DFS(int x,int fa){ 67 68 for(Re int i=head[x];i;i=nxt[i]){ 69 int vv=v[i]; 70 71 if(vv==fa)continue; 72 73 f[vv][0]=x; d[vv][0]=a[vv]; 74 dep[vv]=dep[x]+1; 75 76 DFS(vv,x); 77 } 78 } 79 80 llg getDis(int x,int y){ 81 llg as=0; 82 if(dep[x]<dep[y])swap(x,y); 83 84 Dwn(b,20,0)if(f[x][b]!=-1){ 85 if(dep[f[x][b]]>=dep[y]){ 86 as+=d[x][b]; x=f[x][b]; 87 } 88 } 89 90 if(x==y)return as+a[x]; 91 Dwn(b,20,0)if(f[x][b]!=-1&&f[y][b]!=-1&&f[x][b]!=f[y][b]){ 92 as+=d[x][b]; as+=d[y][b]; 93 x=f[x][b]; y=f[y][b]; 94 } 95 as+=d[x][0]; as+=d[y][0]; 96 97 return as+a[f[x][0]]; 98 } 99 100 llg d00,d10,d01,d11,kd,dx=0,px1,px2; 101 102 int main(){ 103 freopen("forest.in","r",stdin); 104 freopen("forest.out","w",stdout); 105 read(n); 106 For(i,1,n){ 107 read(a[i]); 108 ans=(ans*a[i])%md; 109 pt[i][0]=pt[i][1]=i; dt[i]=a[i]; 110 } 111 For(i,1,n-1){ 112 read(ed[i].a); read(ed[i].b); 113 add(ed[i].a,ed[i].b); 114 } 115 memset(f,-1,sizeof(f)); 116 117 DFS(1,0); 118 119 For(b,1,20) For(i,1,n){ 120 if(f[i][b-1]==-1)continue; 121 122 f[i][b]= f[ f[i][b-1] ][b-1]; 123 d[i][b]= d[ f[i][b-1] ][b-1]+d[i][b-1]; 124 } 125 126 For(i,1,n)pa[i]=i; 127 128 For(i,1,n-1)read(Q[i]); 129 fn[n]=ans; 130 Dwn(i,n-1,1){ 131 int qs=Q[i]; 132 x=ed[qs].a; y=ed[qs].b; 133 int pax=find(x),pay=find(y); 134 135 ans=(ans*Qsm(dt[pax],md-2))%md; 136 ans=(ans*Qsm(dt[pay],md-2))%md; 137 138 if(dt[pax]>dt[pay]){ 139 dx=dt[pax]; px1=pt[pax][0]; px2=pt[pax][1]; 140 }else{ 141 dx=dt[pay]; px1=pt[pay][0]; px2=pt[pay][1]; 142 } 143 144 d00=getDis(pt[pax][0],pt[pay][0]); 145 if(d00>dx)dx=d00,px1=pt[pax][0],px2=pt[pay][0]; 146 147 d10=getDis(pt[pax][1],pt[pay][0]); 148 if(d10>dx)dx=d10,px1=pt[pax][1],px2=pt[pay][0]; 149 150 d01=getDis(pt[pax][0],pt[pay][1]); 151 if(d01>dx)dx=d01,px1=pt[pax][0],px2=pt[pay][1]; 152 153 d11=getDis(pt[pax][1],pt[pay][1]); 154 if(d11>dx)dx=d11,px1=pt[pax][1],px2=pt[pay][1]; 155 156 pt[pax][0]=px1; pt[pax][1]=px2; 157 158 dt[pax]=dx; 159 ans=(ans*dx)%md; 160 pa[pay]=pax; 161 fn[i]=ans; 162 } 163 For(i,1,n){ 164 write(fn[i]); Pn; 165 } 166 return 0; 167 }
转载于:https://www.cnblogs.com/HLAUV/p/9894047.html
花花的森林(倍增,LCA相关推荐
- 洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值
传送门 其实NOIP某些年的第三题也并不是很难嘛... 题目分析: 题目中要求求出某两点之间可以运输的最大重量,也就是这两个点的某条路径上边权最小的边的权值的最大值 很显然,题目中的运输最大重量与选择 ...
- HDU - 3078 Network 倍增LCA
倍增lca,把路径上点全部拉出来拍个序输出第k大就过了. 不知道怎么过的,咱也不敢问. #include<stdio.h> #include<string.h> #includ ...
- BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2144 是 hydro 的 BZOJ ...
- JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林
Description Input Output Sample Input 3 1 2 3 1 2 1 3 2 1 Sample Output 6 9 6 Data Constraint Hint S ...
- 洛谷T1967 货车运输 Kruskal最大生成树倍增LCA
这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值. 于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大. 有了树之后,要求路径,那就要考虑 ...
- [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)
4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MB Submit: 2131 Solved: 865 [Submit][Sta ...
- NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并
思路: Kruskal求最大生成树+倍增LCA // by SiriusRen #include <cstdio> #include <cstring> #include &l ...
- 【Codeforces613D】Kingdom and its Cities【虚树】【Tree DP】倍增lca
http://codeforces.com/problemset/problem/613/D 题意: 给出n个点的树,有q个询问,每次询问给出k个重要的点,问至少删掉多少个非重要的点,使得这个重要的点 ...
- 2019长沙学院新生赛(A水,B水,C(整除分块),D水,E(巧数学),F(二分+bfs),H(换根dp),I(线段树)J(dp+倍增+lca))
A-XOR SUM 通过简单观察得知连续四个数的异或值就是等于0,暴力找出左区间和右区间就可以了,最多跑四个单位 0^1^2^3==0 4^5^6^7=0 #include<bits/std ...
最新文章
- Artificial Intelligence Yourself
- Git每次推送时都会询问用户名
- 基于fiddler的网络爬虫校园网自动登陆系统
- 使用DiskFileItemFactory 实现文件上传 ,设定缓冲区大小和存放临时文件目录。
- IOS 应用中从竖屏模式强制转换为横屏模式
- java 使用logback进行日志输出
- 各种编译环境中如何为C++添加命令行参数(Command-line parameter)
- 如何使用python进行批处理
- Python模块Pygame安装
- 深度学习 --- 随机神经网络详解(玻尔兹曼机学习算法、运行算法)
- Hadoop、Spark等5种大数据框架对比,你的项目该用哪种?
- Qt制作贪吃蛇小游戏
- graphviz安装
- 西湖大学博导:都说不唯论文,那我们发表论文是为了什么?
- 【正则】详解python正则表达式之re.group()用法
- 服装尺寸 html,超完整的各种服装尺寸对照表,总有你需要的
- html里怎么计算梯形周长公式是什么,梯形的周长怎么计算 梯形周长计算公式
- win10 + MuMu 安装与配置frida环境
- Matlab含新能源(风电光伏)和多类型电动汽车配电网风险评估
- tomcat调优-占用内存太多