2018.10.30-dtoj-4009-秀秀的森林(forest)

题目描述:

秀秀有一棵带𝑛个顶点的树𝑇,每个节点有一个点权𝑎-。
有一天,她想拥有两棵树,于是她从𝑇中删去了一条边。
第二天,她认为三棵树或许会更好一些。因此,她又从她拥有的某一棵树中删去了一条边。
如此往复,每一天秀秀都会删去一条尚未被删去的边,直到她得到由𝑛棵只有一个点的树构成的
森林。
秀秀定义一条简单路径(节点不重复出现的路径)的权值为路径上所有点的权值之和,一棵树的
直径为树上权值最大的简单路径。秀秀认为树最重要的特征就是它的直径。所以她想请你算出任一时
刻她拥有的所有树的直径的乘积。因为这个数可能很大,你只需输出这个数对10. + 7取模之后的结
果即可。

输入:

输入的第一行包含一个整数𝑛,表示树𝑇上顶点的数量。
下一行包含𝑛个空格分隔的整数𝑎-,表示顶点的权值。
之后的𝑛 − 1行中,每一行包含两个用空格分隔的整数𝑢-和𝑣-,表示节点𝑢-和𝑣-之间连
有一条边,编号为𝑖。
再之后𝑛 − 1行中,每一行包含一个整数𝑘6,表示在第𝑗天里会被删除的边的编号。

输出:

共𝑛行,在第𝑖行,输出删除𝑖 − 1条边之后,所有树直径的乘积对10. + 7取模的结果。

数据范围:

对于40%的数据:𝑛 ≤ 100;
另有20%的数据:𝑛 ≤ 1000;
另有20%的数据:𝑛 ≤ 10000;
对于100%的数据:𝑛 ≤ 100000,𝑎- ≤ 10000。

算法标签:LCA,倍增

思路:

两棵树合并时,树的直径只有可能由原来两棵树直径两边的点构成,所以枚举四个点构成的直径比较大小(在原树中利用lca比较log效率)。然后就一直把树合起来就行了。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e5+5,p=1e9+7;LL res[N],sum=1,g[N],s[N];
int n,a[N],head[N],ne[N<<1],to[N<<1],cnt,k[N],pi[2][N],f[N][20],d[N],fa[N],len[N];
struct node{int l,r;}t[N];
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;}
il LL ksm(LL a,int y){LL b=1;while(y){if(y&1)b=b*a%p;a=a*a%p;y>>=1;}return b;}
il int getfa(int x){if(fa[x]==0)return x;return fa[x]=getfa(fa[x]);}
il void dfs(int x){
    for(int i=head[x];i;i=ne[i]){
        if(f[x][0]==to[i])continue;
        s[to[i]]=s[x]+(LL)a[to[i]];d[to[i]]=d[x]+1;
        f[to[i]][0]=x;dfs(to[i]);
    }
}
il void init(){
    for(int i=1;i<=18;i++)for(int j=1;j<=n;j++)
        f[j][i]=f[f[j][i-1]][i-1];
}
il int LCA(int x,int y){
    if(d[x]<d[y])swap(x,y);LL res=0;
    for(int i=18;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
    if(x==y)return x;
    for(int i=18;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    n=read();for(int i=1;i<=n;i++)a[i]=read(),g[i]=a[i];
    for(int i=1;i<n;i++){
        t[i].l=read(),t[i].r=read();
        insert(t[i].l,t[i].r);insert(t[i].r,t[i].l);
    }
    d[1]=1;s[1]=a[1];dfs(1);init();
    for(int i=1;i<n;i++)k[i]=read();
    for(int i=1;i<=n;i++)sum=sum*(LL)a[i]%p;res[n]=sum;
    for(int i=1;i<=n;i++)pi[0][i]=pi[1][i]=i,len[i]=1;
    for(int i=n-1;i;i--){
        int x=getfa(t[k[i]].l),y=getfa(t[k[i]].r);
        LL r=0;int t1,t2;sum=sum*ksm((LL)g[x],p-2)%p*ksm((LL)g[y],p-2)%p;
        for(int k1=0;k1<2;k1++){
            for(int k2=0;k2<2;k2++){
                int xx=pi[k2][x],yy=pi[k1][y];
                int lca=LCA(xx,yy);LL qq=s[xx]+s[yy]-s[lca]-s[f[lca][0]];
                if(qq>r)r=qq,t1=xx,t2=yy;
            }
        }
        if(len[x]>r)r=len[x],t1=pi[0][x],t2=pi[1][x];
        if(len[y]>r)r=len[y],t1=pi[0][y],t2=pi[1][y];
        pi[0][x]=t2;pi[1][x]=t1;g[x]=r;fa[y]=x;len[x]=r;
        sum=sum*r%p;res[i]=sum;
    }
    for(int i=1;i<=n;i++)printf("%lld\n",res[i]);
  return 0;
}
View Code

 

posted @ 2018-10-30 17:02  Jessiejzy  阅读(310)  评论(0编辑  收藏  举报