[羅区2664]木々ゲーム

ポータル

点在し、実際には、そこにいるように見えます\(O(N)\)の練習?
実際に、私はちょうどので、点線の結果で書かれ、それを書きたくない焼け感じています

解答の色の貢献を考えてみましょう。

色が削除されたツリーで、この点を考慮して、そこの木の多くは、寄与しない互いの間の点でこれらの木になりますが、別の木の2点間に貢献しています。

したがって、我々はすべての色を得ることができ、合計点の値はnである - どこ木の大きさ。

各色の小さな木のサイズ - これにより、点が色のn個の*の数の合計です。

私たちは小さなツリーのサイズ、ノードの最小深さがあり、そして後者は、カバレッジを達成するために、ツリー差を使用することができます考えます。

ああ、おそらく仮想ツリーでそれが可能であり、しかし、私はしません
それでは、どのサイズ要件?私のようなファック、話すことができません

#include<bits/stdc++.h>
#define LL long long
#define re register
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=100002;
const int M=N<<1;
int n,a[N];
int cnt,head[N],Next[M],v[M];

inline void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

void add(int x,int y){
    Next[++cnt]=head[x];
    head[x]=cnt;
    v[cnt]=y;
}

int sz[N],f[N],pre[N];
LL tag[N],c[N];
void dfs(int x,int fa){
    sz[x]=1;f[x]=pre[a[x]];
    for(re int i=head[x];i;i=Next[i])
     if (v[i]!=fa){
        pre[a[x]]=v[i];
        dfs(v[i],x);
        tag[v[i]]+=sz[v[i]];
        sz[x]+=sz[v[i]];
     }
    tag[f[x]]-=sz[x];
    if (f[x]==1) c[a[x]]-=sz[x];
    pre[a[x]]=f[x];
}

LL sum[N];
void dfs(int x,int fa,LL s){
    int cc=c[a[x]];
    s+=tag[x]-cc;
    sum[x]=s;
    for(re int i=head[x];i;i=Next[i])
     if (v[i]!=fa){
        c[a[x]]=tag[v[i]];
        dfs(v[i],x,s);
     }
    c[a[x]]=cc;
}

int b[N];
int main(){
    read(n);
    fr(i,1,n) read(a[i]),b[a[i]]=1;
    int x,y;
    fr(i,2,n){
        read(x);read(y);
        add(x,y);add(y,x);
    }
    //fr(i,1,100000) ver[i].push_back(0);
    int tot=0;
    fr(i,1,100000) if (b[i]) tot++,pre[i]=1,c[i]=n;
    tag[1]=1LL*tot*n;
    dfs(1,0);
    dfs(1,0,0);
    fr(i,1,n) printf("%lld\n",1LL*n*tot-sum[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/ymzqwq/p/11286736.html