BZOJ 3572: [Hnoi2014]世界樹

BZOJ 3572: [Hnoi2014]世界樹

標籤(空格分隔): OI-BZOJ OI-虛數 OI-樹形dp OI-倍增ios


Time Limit: 20 Sec
Memory Limit: 512 MBc++


Descriptionpost

世界樹是一棵無比巨大的樹,它伸出的枝幹構成了整個世界。在這裏,生存着各類各樣的種族和生靈,他們共同信奉着絕對公正公平的女神艾莉森,在他們的信條裏,公平是使世界樹可以生生不息、持續運轉的根本基石。
世界樹的形態能夠用一個數學模型來描述:世界樹中有n個種族,種族的編號分別從1到n,分別生活在編號爲1到n的聚居地上,種族的編號與其聚居地的編號相同。有的聚居地之間有雙向的道路相連,道路的長度爲1。保證鏈接的方式會造成一棵樹結構,即全部的聚居地之間能夠互相到達,而且不會出現環。定義兩個聚居地之間的距離爲鏈接他們的道路的長度;例如,若聚居地a和b之間有道路,b和c之間有道路,由於每條道路長度爲1並且又不可能出現環,所臥a與c之間的距離爲2。
出於對公平的考慮,第i年,世界樹的國王須要受權m[i]個種族的聚居地爲臨時議事處。對於某個種族x(x爲種族的編號),若是距離該種族最近的臨時議事處爲y(y爲議事處所在聚居地的編號),則種族x將接受y議事處的管轄(若是有多個臨時議事處到該聚居地的距離同樣,則y爲其中編號最小的臨時議事處)。
如今國王想知道,在q年的時間裏,每年完成受權後,當年每一個臨時議事處將會管理多少個種族(議事處所在的聚居地也將接受該議事處管理)。 如今這個任務交給了以智慧著稱的靈長類的你:程序猿。請幫國王完成這個任務吧。spa

Inputcode

第一行爲一個正整數n,表示世界樹中種族的個數。
接下來n-l行,每行兩個正整數x,y,表示x聚居地與y聚居地之間有一條長度爲1的雙
向道路。接下來一行爲一個正整數q,表示國王詢問的年數。
接下來q塊,每塊兩行:
第i塊的第一行爲1個正整數m[i],表示第i年受權的臨時議事處的個數。
第i塊的第二行爲m[i]個正整數h[l]、h[2]、…、h[m[i]],表示被受權爲臨時議事處的聚居地編號(保證互不相同)。ip

Outputget

輸出包含q行,第i行爲m[i]個整數,該行的第j(j=1,2…,,m[i])個數表示第i年被受權的聚居地h[j]的臨時議事處管理的種族個數。數學

Sample Inputstring

10it

2 1

3 2

4 3

5 4

6 1

7 3

8 3

9 4

10 1

5

2

6 1

5

2 7 3 6 9

1

8

4

8 7 10 3

5

2 9 3 5 8
Sample Output

1 9

3 1 4 1 1

10

1 1 3 5

4 1 3 1 1
HINT

N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000


Solution

虛樹,竟然到如今才搞,真的太弱了,參考神牛http://lazycal.logdown.com/posts/202331-bzoj3572
orz


Code

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define MP(a,b) make_pair(a,b)
#define PA pair<int,int>
int read()
{
    int s=0,f=1;char ch=getchar();
    while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
const int N=300005;
int n,m;
int be[N],bn[N*2],bv[N*2],bl[N*2],bw=1;
void put(int u,int v,int l)
{bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;}
int dep[N],dep2[N],siz[N];
int dfn[N],rank[N],dtot;
int fa[N][19];
int h[N],t[N],tot;
void dfs(int x)
{
    dfn[rank[x]=++dtot]=x;
    siz[x]=1;
    for(int i=be[x],v;i;i=bn[i])
        if(!siz[v=bv[i]])
           {fa[v][0]=x;
            for(int j=0;fa[v][j+1]=fa[fa[v][j]][j];j++);
            dep[v]=dep[x]+bl[i];
            dep2[v]=dep[x]+1;
            dfs(v);
            siz[x]+=siz[v];
           }
}
int lca(int a,int b)
{
    if(dep2[a]<dep2[b])swap(a,b);
    for(int i=18;i>=0;i--)
        if(dep2[fa[a][i]]>=dep2[b])
            a=fa[a][i];
    for(int i=18;i>=0;i--)
        if(fa[a][i]!=fa[b][i])
            a=fa[a][i],b=fa[b][i];
    return a==b?a:fa[a][0];
}
int jump(int x,int dis)
{
    for(int i=18;i>=0;i--)
        if(dep[fa[x][i]]>dis)
            x=fa[x][i];
    return x;
}
bool cmp(int a,int b)
{
    return rank[a]<rank[b];
}
int sta[N],top;
int father[N],ans[N],val[N],hh[N];
PA md[N];
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    n=read();
    for(int i=1;i<n;i++)
       {int u=read(),v=read();
        put(u,v,1);
        put(v,u,1);
       }
    dep[0]=dep2[0]=-1;
    dfs(1);
    for(int Q=read();Q--;)
       {m=read();tot=0;
        for(int i=1;i<=m;i++)
           {hh[i]=h[i]=read(),
            md[h[i]]=MP(0,h[i]);
            t[++tot]=h[i];
            ans[h[i]]=0;
           }
        sort(&h[1],&h[m+1],cmp);
        top=0;
        for(int i=1;i<=m;i++)
           {int now=h[i];
            if(!top){father[sta[++top]=now]=0;continue;}
            int LCA=lca(sta[top],now);
            for(;dep[sta[top]]>dep[LCA];top--)
                if(dep[sta[top-1]]<=dep[LCA])
                    father[sta[top]]=LCA;
            if(sta[top]!=LCA)
               {t[++tot]=LCA;
                father[LCA]=sta[top];
                md[LCA]=MP(0x3f3f3f3f,0);
                sta[++top]=LCA;
               }
            father[now]=sta[top];
            sta[++top]=now;
           }
        for(int i=1;i<=tot;i++)val[t[i]]=siz[t[i]];
        sort(&t[1],&t[tot+1],cmp);
        for(int i=tot;i>1;i--)
           {int x=t[i],f=father[x];
            md[f]=min(md[f],MP(dep[x]-dep[f]+md[x].first,md[x].second));
           }
        for(int i=2;i<=tot;i++)
           {int x=t[i],f=father[x];
            md[x]=min(md[x],MP(dep[x]-dep[f]+md[f].first,md[f].second));
           }
        for(int i=1;i<=tot;i++)
           {int x=t[i],f=father[x];
            if(i==1)
               {ans[md[x].second]+=n-siz[x];
                continue;
               }
            int u=jump(x,dep[f]);
            val[f]-=siz[u];
            if(md[f].second==md[x].second)
               {ans[md[f].second]+=siz[u]-siz[x];
                continue;
               }
            int mid=jump(x,(md[x].first-md[f].first+dep[x]+dep[f]-(md[x].second<md[f].second))/2);
            ans[md[f].second]+=siz[u]-siz[mid];
            ans[md[x].second]+=siz[mid]-siz[x];
           }
        for(int i=1;i<=tot;i++)
            ans[md[t[i]].second]+=val[t[i]];
        for(int i=1;i<=m;i++)
            printf("%d ",ans[hh[i]]);printf("\n");
       }
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}
相關文章
相關標籤/搜索