花花的森林,嗯,这是一篇正经的题解。
模拟考的时候没有看出来要怎么求啊,暴力地树形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(' ') 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 }