zoukankan      html  css  js  c++  java
  • 花花的森林(倍增,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('
    ')
     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 }
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9894047.html
Copyright © 2011-2022 走看看