花花的森林(倍增,LCA
花花的森林,嗯,这是一篇正经的题解。
模拟考的时候没有看出来要怎么求啊,暴力地树形DP、换根、合并、求直径。居然也险险地拿到了80分,不过我们要正经地想正解。
容易想到我们可以让时光倒流,让空间扭转,离线地从最后一次操作往前,这样删边就变成加边了(合并总比拆开好做吧)
首先,我们要知道,两棵树合并后,新直径的两个端点一定是原来两棵树的两个直径的四个不同端点中的某两个(为什么?),自己画一下图,思考证明一下,这个结论并不难得出。
所以说合并时的新直径就只会有六种即 C(4,2),那么我们分别求出这六个直径的值(当然原本的两种不用求),用最大的作为新树的直径就好啦~,并且记下此时的两个端点。
那要怎么求直径啊~?
当然是倍增啦。
可是可是,我们都把树拆成一棵棵了,怎么倍增啊,合并后不是还要重新算一次倍增的数组吗?
我们可以在原树上倍增呀,没必要真的把树拆了(如果题目让你做什么你就做什么,一定会被带离正解的),在一棵树上,两点之间的简单路径是唯一的。
(那你真是个小机灵鬼~)
然后合并就用并查集维护。
哦对了,还有一个细节,从后往前做我们会遇到除法的问题(难不成你要循环一遍整个森林求一次ans吗)所以在模质数的意义下,使用费马小定理求逆元来进行除法。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm> #define For(i,a,b) for(register int i=a;i<=b;++i)
#define Dwn(i,a,b) for(register int i=a;i>=b;--i)
#define Re register
#define Pn putchar('\n')
#define llg long long
using namespace std;
const int N=1e5+,md=1e9+;
llg a[N],ans=,dt[N],pt[N][],fn[N];
int head[N],nxt[N*],v[N*],cnt=;
int pa[N],sz[N],n,m,x,y,Q[N];
int f[N][];
llg d[N][];
struct EDG{
int a,b;
}ed[N];
inline void read(int &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
inline void read(llg &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
void write(llg x){
if(x>)write(x/);
int xx=x%;
putchar(xx+'');
}
int find(int x){
int r=x;
while(pa[r]!=r)r=pa[r];
int i,j;
i=x;
while(pa[i]!=r){
j=pa[i]; pa[i]=r; i=j;
}
return r;
}
void add(int ux,int vx){
cnt++;
nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx;
cnt++;
nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux;
}
llg Qsm(llg x,int k){
llg ans=;
while(k){
if(k&)ans=(ans*x)%md;
x=(x*x)%md;
k>>=;
}
return ans;
} int dep[N];
void DFS(int x,int fa){ for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i]; if(vv==fa)continue; f[vv][]=x; d[vv][]=a[vv];
dep[vv]=dep[x]+; DFS(vv,x);
}
} llg getDis(int x,int y){
llg as=;
if(dep[x]<dep[y])swap(x,y); Dwn(b,,)if(f[x][b]!=-){
if(dep[f[x][b]]>=dep[y]){
as+=d[x][b]; x=f[x][b];
}
} if(x==y)return as+a[x];
Dwn(b,,)if(f[x][b]!=-&&f[y][b]!=-&&f[x][b]!=f[y][b]){
as+=d[x][b]; as+=d[y][b];
x=f[x][b]; y=f[y][b];
}
as+=d[x][]; as+=d[y][]; return as+a[f[x][]];
} llg d00,d10,d01,d11,kd,dx=,px1,px2; int main(){
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
read(n);
For(i,,n){
read(a[i]);
ans=(ans*a[i])%md;
pt[i][]=pt[i][]=i; dt[i]=a[i];
}
For(i,,n-){
read(ed[i].a); read(ed[i].b);
add(ed[i].a,ed[i].b);
}
memset(f,-,sizeof(f)); DFS(,); For(b,,) For(i,,n){
if(f[i][b-]==-)continue; f[i][b]= f[ f[i][b-] ][b-];
d[i][b]= d[ f[i][b-] ][b-]+d[i][b-];
} For(i,,n)pa[i]=i; For(i,,n-)read(Q[i]);
fn[n]=ans;
Dwn(i,n-,){
int qs=Q[i];
x=ed[qs].a; y=ed[qs].b;
int pax=find(x),pay=find(y); ans=(ans*Qsm(dt[pax],md-))%md;
ans=(ans*Qsm(dt[pay],md-))%md; if(dt[pax]>dt[pay]){
dx=dt[pax]; px1=pt[pax][]; px2=pt[pax][];
}else{
dx=dt[pay]; px1=pt[pay][]; px2=pt[pay][];
} d00=getDis(pt[pax][],pt[pay][]);
if(d00>dx)dx=d00,px1=pt[pax][],px2=pt[pay][]; d10=getDis(pt[pax][],pt[pay][]);
if(d10>dx)dx=d10,px1=pt[pax][],px2=pt[pay][]; d01=getDis(pt[pax][],pt[pay][]);
if(d01>dx)dx=d01,px1=pt[pax][],px2=pt[pay][]; d11=getDis(pt[pax][],pt[pay][]);
if(d11>dx)dx=d11,px1=pt[pax][],px2=pt[pay][]; pt[pax][]=px1; pt[pax][]=px2; dt[pax]=dx;
ans=(ans*dx)%md;
pa[pay]=pax;
fn[i]=ans;
}
For(i,,n){
write(fn[i]); Pn;
}
return ;
}
花花的森林(倍增,LCA的更多相关文章
- 【Luogu】P1967货车运输(最大生成森林+倍增LCA)
题目链接 倍增LCA是个什么蛇皮原理啊,循环完了还得再往上跳一次才能到最近公共祖先 合着我昨天WA两次就是因为这个 建最大生成森林,因为图不一定是联通的,所以不一定是一棵树.这个地方用克鲁斯卡尔就好了 ...
- 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)
5286. [NOIP2017提高A组模拟8.16]花花的森林 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Descript ...
- 货车运输(最大生成树+倍增LCA)
看到第一篇题解的神奇码风--我决定发一篇码风正常的题解造福人类 这题的做法也非常经典,最大生成树\(+LCA\),相当于先贪心一下,在LCA的时候记录一下当前最小的边权 顺便吐槽一下最后一个测试点: ...
- 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA
题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物 ...
- 【bzoj4242】水壶 BFS+最小生成树+倍增LCA
题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入 ...
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]
题目描述 Farmer John has installed a new system of pipes to transport milk between the stalls in his b ...
- Gym100685G Gadget Hackwrench(倍增LCA)
题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...
随机推荐
- Flow 的工作方式 类型检查
Vue.js 技术揭秘 | Vue.js 技术揭秘 https://ustbhuangyi.github.io/vue-analysis/ Vue技术内幕 http://hcysun.me/vue-d ...
- 一起来学linux:FTP服务器搭建
首先安装vsftpd: apt install vsftpd有下面几个重要的配置文件:1 /etc/vsftpd.conf. 这个是vsftpd的配置文件.通过“参数=设置值”的方式来设置的. 2 / ...
- java中科学计数法数字转字符串
开发过程中有可能会遇到很小的数字,在显示过程中就转换成了科学计数法,这种不利于人的观看,于是就有必要转成字符串形式的.so. 将科学计数法的数字转换成字符串: 使用的是java.math的BigDec ...
- guava cache与spring集成
缓存的背景 缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间.在cpu进行计算的时候, 首先是读取寄存器,然后内存,再是硬盘.由 ...
- CSS控制文本的长度,超过一行显示省略号
代码如下: <div style="width:100px;height:20px;text-overflow:ellipsis; white-space:nowrap; overfl ...
- html5--5-3 给直线添加样式
html5--5-3 给直线添加样式 学习要点 strokeStyle属性:设置颜色.渐变或模式(本节课只涉及到颜色) lineWidth属性:--设置线宽 Canvas的路径方法 moveTo() ...
- margin-top 为什么会影响父元素的 margin-top
1.原因: In this specification, the expression collapsing margins means that adjoining margins (no non ...
- Android终端管理器删除文件夹
终端管理器删除文件夹不能用网上提供的: rm -rf 文件夹名 而要用: rm -r 文件夹名. http://blog.csdn.net/enhancing/article/details/8490 ...
- Kvm学习文档记录
一.实验环境: 在vmware上打开vt支持选项: 操作系统信息: [root@node2 ~]# cat /etc/issue CentOS release 6.6 (Final) Kernel \ ...
- css font-family(字体样式)
之前因为用的很少,所以没注意,最近做APP混合开发, 给字体一个样式 font-family:" 微软雅黑": 发现在有的手机上有效,但是在有的手机上是无效的, 解决方法: ...