Fork me on GitHub

花花的森林(倍增,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 }

 

posted @ 2018-11-02 08:03  H_LAUV  阅读(273)  评论(0编辑  收藏  举报
Live2D //博客园自带,可加可不加