【gdgzezoi】問題C:冬の風

説明

Nポイントツリーが与えられると、ツリー内の各ノードに対して、それが削除され、その後、森のいずれか1つが各点について、父親が切断及び他のツリーに接続されたポイントを得ることができますフォレスト内のすべてのツリーの最大サイズの最小値を求めます。

入力

最初の行数n。

二つの整数の2〜N + 1ラインで、(1 <= X <= Y <= n)を、YをX、Yは、(次にyがルートであるx = 0の場合)は、xの父親である表わします。

出力

数のn行の総数、i行目の答えは、私は省略点を表します。

サンプル入力

10

0 1

1 2

1 3

1 4

2 5

2 6

3 7

4 8

4 9

5 10

サンプル出力

3

4

5

5

5

9

9

9

9

9

ヒント

10データの%、N <= 10

データの30%、N <= 10 ^ 3

100%のデータ、N <= 10 ^ 5

思考

まず、どのように答えを求めているのポイントを検討してください。オーダーサイズ[i]を表すサブツリーと点I、minとmaxは森の木の最大サイズを表し、森の木の最小サイズを表します。その後、我々はサイズ[i]が+min≤ansおよび最大サイズ[i]の≤ans、すなわち最大-ans≤size[i]のことを、私はツリーの最大のポイントがあるかどうかを疑問に、ANS半分に答えることができ≤ ANS-分。
ボーダーの半分に注意してください。

最初から再びルートをDFS、および4つのマップのメンテナンス:

MapPathの:すべてのポイントのポイントサイズへのルートから私の父

mapheaviest:サブツリーポイントiの再サイズのすべてのポイントの息子

マップライト:すべての点の大きさの点Iサブツリー光のすべての息子

mapother:上記のポイント他のすべての点に加えて、サイズマップ

私が見つけたときの答えは、プランテーション最大の木であるこの点を削除するかを決定するポイント:

息子が重いi点、ダイレクト半分である場合は、mapheaviest上のクエリに対する答えを見つけることができます。

ルートは、特別な文を見て、その後、ルートから、私は彼の父のパス上のすべてのポイントサイズを削除した後、私はサイズを減算したいポイントで[i]が原因である場合。mapother上の他の可能なクエリ。

次は、4つのマップを維持する方法を検討してください。

MapPathの:更新DFSは、あなたが終了すると削除することができます。

mapheaviset、マップライト:ヒューリスティックマージツリーが必要になることがあります。

mapother:最初にすべてのポイントが含まれている、他のマップでは、この点がポイントを追加、削除します。

Oの時間複雑(nlogn)

コード

#include<bits/stdc++.h>
using namespace std;
#define it map<int,int>::iterator 
map<int,int> mp[4];
vector<int> v[100010];
int size[100010],son[100010],mn[100010],mx2[100010],ans[100010],n,m,rt;
void add(int x,int y,int hh)
{
    mp[hh][x]+=y;mp[3][x]-=y;
    if (!mp[3][x]) mp[3].erase(x);
    if (!mp[hh][x]) mp[hh].erase(x);
}
  
void insert(int x,int y,int hh)
{
    add(size[x],y,hh);
    for (int i=0;i<v[x].size();i++) insert(v[x][i],y,hh);
}
  
int find(int x,int y,int l,int r,int hh,int z)
{
    if (x==y&&x>=l&&x<=r) return x;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        it t=mp[hh].lower_bound(y-mid+z);
        if (t!=mp[hh].end()&&t->first<=mid-x+z) r=mid-1;
        else l=mid+1;
    }
    return l;
}
  
void work(int x)
{
    if (size[x]==n) ans[x]=find(mn[x],size[son[x]],mx2[x],size[son[x]],1,0);
    else if (size[son[x]]>n-size[x]) ans[x]=find(min(mn[x],n-size[x]),size[son[x]],max(n-size[x],mx2[x]),size[son[x]],1,0);
    else if (!son[x]) ans[x]=n-size[x];
    else ans[x]=min(find(mn[x],n-size[x],size[son[x]],n-size[x],0,size[x]),find(mn[x],n-size[x],size[son[x]],n-size[x],3,0));
}
  
void pre(int x)
{
    size[x]=1;mn[x]=n;
    for (int i=0;i<v[x].size();i++)
    {
        pre(v[x][i]);
        size[x]+=size[v[x][i]];
        mn[x]=min(mn[x],size[v[x][i]]);
        if (size[v[x][i]]>size[son[x]]) mx2[x]=size[son[x]],son[x]=v[x][i];
        else if (size[v[x][i]]>mx2[x]) mx2[x]=size[v[x][i]];
    }
    mp[3][size[x]]++;
    if (size[x]<n) mn[x]=min(mn[x],n-size[x]);
}
  
void dfs(int x,bool bo)
{
    add(size[x],1,0);
    for (int i=0;i<v[x].size();i++) if (v[x][i]!=son[x]) dfs(v[x][i],0);
    if (son[x]) dfs(son[x],1);
    for (int i=0;i<v[x].size();i++) if (v[x][i]!=son[x]) insert(v[x][i],1,2);
    if (!(--mp[0][size[x]])) mp[0].erase(size[x]);
    work(x);
    mp[3][size[x]]++;
    if (bo)
    {
        add(size[x],1,1);
        for (it t=mp[2].begin();t!=mp[2].end();)
        {
            mp[1][t->first]+=t->second;
            mp[2].erase(t++);
        }
    }
    else for (int i=0;i<v[x].size();i++)
    {
        int t=v[x][i];
        if (t!=son[x]) insert(t,-1,2);
        else insert(t,-1,1);
    }
}
  
int main()
{
    scanf("%d",&n);
    if (n==1) { puts("0");return 0; }
    for (int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x) v[x].push_back(y);
        else rt=y;
    }
    pre(rt);dfs(rt,1);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}
703元記事公開 ウォンの賞賛392 ビューに14万+を

おすすめ

転載: blog.csdn.net/Eric1561759334/article/details/100552736