花花的森林,嗯,这是一篇正经的题解。

模拟考的时候没有看出来要怎么求啊,暴力地树形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的更多相关文章

  1. 【Luogu】P1967货车运输(最大生成森林+倍增LCA)

    题目链接 倍增LCA是个什么蛇皮原理啊,循环完了还得再往上跳一次才能到最近公共祖先 合着我昨天WA两次就是因为这个 建最大生成森林,因为图不一定是联通的,所以不一定是一棵树.这个地方用克鲁斯卡尔就好了 ...

  2. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

  3. JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)

    5286. [NOIP2017提高A组模拟8.16]花花的森林 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Descript ...

  4. 货车运输(最大生成树+倍增LCA)

    看到第一篇题解的神奇码风--我决定发一篇码风正常的题解造福人类 这题的做法也非常经典,最大生成树\(+LCA\),相当于先贪心一下,在LCA的时候记录一下当前最小的边权 顺便吐槽一下最后一个测试点: ...

  5. 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA

    题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物 ...

  6. 【bzoj4242】水壶 BFS+最小生成树+倍增LCA

    题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入 ...

  7. [板子]倍增LCA

    倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...

  8. 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

  9. Gym100685G Gadget Hackwrench(倍增LCA)

    题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...

随机推荐

  1. 不懂不能装懂--邮箱后缀“inc”的含义

    之前实习的公司,邮箱域名是XXX@XXX-inc.com 再之前,投递简历了或者关注某个公司的一些信息或者和这些公司的人邮件联系是也发现有这个inc的后缀,一直不明白,今天觉得自己找到答案了,不怕丢人 ...

  2. linux应用之mysql数据库的安装及配置(centos)

    CentOS下Mysql数据库的安装与配置   如果要在Linux上做j2ee开发,首先得搭建好j2ee的开发环境,包括了jdk.tomcat.eclipse的安装(这个在之前的一篇随笔中已经有详细讲 ...

  3. elasticsearch function_score Query——文档排序结果的最后一道墙

    function_score Query The function_score query is the ultimate tool for taking control of the scoring ...

  4. Linux vSphere SDK for Perl 执行脚本报错

      本人在gentoo系统上安装完vSphere for Perl之后,执行/usr/lib/vmware-viperl/app/vm/vminfo.pl脚本. 提示错误如下: Server vers ...

  5. 安装asterisk以及asterisk-gui

           asterisk的安装在ubuntu上自我感觉还是很方便的,虽然也会遇到一些小的问题.下面是本人遇到的   一些问题和解决方法.     1>在ubuntu10.04上安装aste ...

  6. Dom4J 解析xml ,类查询

    /** * 从XML文件比对,传入provinceId 返回 provinceShortName * @param provinceid * @return */ public static Stri ...

  7. BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree

    BZOJ_1941_[Sdoi2010]Hide and Seek_KDtree Description 小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得 ...

  8. windows下多进程加协程并发模式

    好久没更新博客了.正好最近要整理一下最近这段时间做过的项目以及学习python的一些心得.如标题所示,今天就来说说windows下多进程加协程并发模式.其实网上还是蛮多在linux下的多进程加协程并发 ...

  9. button的FlatStyle和FlatAppearance属性

    FlatStyle是处理边框的样式,而FlatAppearance是用来设置边框的颜色,宽度和鼠标移动和点击时的效果设置FlatStyle为Flat,并且设置FlatAppearance下的Borde ...

  10. web单机优化

    又得开始写博客了,目测又要一周一篇了,当然了这不算python跟前端的,个人喜欢notepad++可惜不能放图片,word什么的太讨厌了 为什么要单机优化呢,很简单,因为不论以后是各类集群也好,物理机 ...