花花的森林(倍增,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步经过边的 ...
随机推荐
- LeetCode算法题目解答汇总(转自四火的唠叨)
LeetCode算法题目解答汇总 本文转自<四火的唠叨> 只要不是特别忙或者特别不方便,最近一直保持着每天做几道算法题的规律,到后来随着难度的增加,每天做的题目越来越少.我的初衷就是练习, ...
- HTML 常用组件
1.下拉选择 <select id="select" name="select" class="form-control"> & ...
- REUSE_ALV_GRID_DISPLAY_LVC 的user_command
*&--------------------------------------------------------------------* *& Form CALL_FUNCTIO ...
- SpringBoot-(8)-配置MySQL数据库链接,配置数据坚挺拦截,创建默认数据表
一,链接mysql数据库 # 数据源基本配置 spring.datasource.username=root spring.datasource.password=123456 spring.data ...
- mac10.10 打造Python多版本虚拟环境
一.简介 1.在操作系统mac10.10(yosemite)中搭建Python多版本虚拟环境: 2.多版本虚拟环境包含三个含义: 在一个操作系统中安装多个版本的Python,不同版本可以随意切换,例如 ...
- Appium——WebDriverException: Message: A new session could not be created.
每次启动完一次脚本再次启动的时候会报这个错误,会话没有被创建 查看了下Appium日志: 查看下设备是否准备好,我用的是模拟器,就cmd下查看下设备: 可以看到设备掉线了... 好吧,重启下设备 脚本 ...
- 记录下 hubot相关
适配器工厂https://hubot.github.com/docs/adapters/ 自己写适配器https://hubot.github.com/docs/adapters/developmen ...
- 英语发音规则---gh
英语发音规则---gh 一.总结 一句话总结:gh字母组合的读音在中学英语课本中归纳起来主要有"发音"和"不发音"两种情况. gh字词首是发/g/,因为需要开头 ...
- (转)使用cygwin注意事项一
原文出处:http://gotgit.readthedocs.io/en/latest/01-meet-git/050-install-on-windows-cygwin.html 在Windows下 ...
- [HAOI 2012] 容易题
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2751 [算法] 考虑k = 0的情况 , 根据乘法原理 : Ans = (n * ( ...