zoukankan      html  css  js  c++  java
  • bzoj 3572: [Hnoi2014]世界树 虚树 && AC500

    3572: [Hnoi2014]世界树

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 520  Solved: 300
    [Submit][Status][Discuss]

    Description

     世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
        世界树的形态可以用一个数学模型来描述:世界树中有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年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

    Input

        
        第一行为一个正整数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]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

    Output

        输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

    Sample Input

    10
    21
    32
    43
    54
    61
    73
    83
    94
    10 1
    5
    2
    61
    5
    27369
    1
    8
    4
    87103
    5
    29358

    Sample Output


    19
    31411
    10
    1135
    41311
     
     
      只要知道虚树这个东西,其实这道题的解法还是很容易想到的,由于建了虚树后一条边最多被分成两部分,分界点离两点距离相等,可以用树形DP解决。
      因此本题难点在于如何建虚树。我的做法是将所有点按照dfs序排序,依次加点,通过一个栈维护最右边的链。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cassert>
    using namespace std;
    #define MAXN 602100
    #define MAXE MAXN*2
    #define MAXV MAXN
    #define INF 0x3f3f3f3f
    int n,m;
    struct Edge
    {
            int np;
            Edge *next;
    }*V[MAXV],E[MAXE];
    int tope=-1;
    void addedge(int x,int y)
    {
            E[++tope].np=y;
            E[tope].next=V[x];
            V[x]=&E[tope];
    }
    int q[MAXN];
    int pnt[MAXN];
    int depth[MAXN];
    int siz[MAXN];
    void bfs(int now)
    {
            int head=-1,tail=0;
            Edge *ne;
            pnt[now]=now;
            q[0]=now;
            while(head<tail)
            {
                    now=q[++head];
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now])continue;
                            pnt[ne->np]=now;
                            depth[ne->np]=depth[now]+1;
                            q[++tail]=ne->np;
                    }
            }
            for (int i=tail;i>=0;i--)
            {
                    now=q[i];
                    siz[now]=1;
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now])continue;
                            siz[now]+=siz[ne->np];
                    }
            }
    }
    int jump[20][MAXN];
    void init_lca()
    {
            for (int i=1;i<=n;i++)
                    jump[0][i]=pnt[i];
            for (int j=1;j<20;j++)
                    for (int i=1;i<=n;i++)
                            jump[j][i]=jump[j-1][jump[j-1][i]];
    }
    int swim(int now,int dep)
    {
            for (int i=0;i<20;i++)
                    if (dep&(1<<i))
                            now=jump[i][now];
            return now;
    }
    int lca(int x,int y)
    {
            if (depth[x]<depth[y])swap(x,y);
            int dep=depth[x]-depth[y];
            for (int i=0;i<20;i++)
                    if (dep&(1<<i))
                            x=jump[i][x];
            if (x==y)return x;
            for (int i=19;i>=0;i--)
                    if (jump[i][x]!=jump[i][y])
                            x=jump[i][x],y=jump[i][y];
            return pnt[x];
    }
    int dis(int x,int y)
    {
            return depth[x]+depth[y]-2*depth[lca(x,y)];
    }
    int stack[MAXN],tops=-1;
    int pos[MAXN],dfstime;
    void dfs(int now)
    {
            Edge *ne;
            stack[++tops]=now;
            while (~tops)
            {
                    now=stack[tops--];
                    pos[now]=++dfstime;
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now])continue;
                            stack[++tops]=ne->np;
                    }
            }
    }
    int seq[MAXN];
    int tot[MAXN];
    struct qur_t
    {
            int id;
            int index;
    }ql[MAXN];
    bool cmp_pos(qur_t q1,qur_t q2)
    {
            return pos[q1.index]<pos[q2.index];
    }
    bool cmp_id(qur_t q1,qur_t q2)
    {
            return q1.id<q2.id;
    }
    struct edge
    {
            int x,y,v;
            int dx,dy,gx,gy;
            edge(){}
            edge(int x,int y,int v):x(x),y(y),v(v){}
    };
    namespace task2
    {
            const int maxn=MAXN;
            const int maxe=maxn;
            const int maxv=maxn*2;
            struct Edge
            {
                    int np;
                    int val;
                    Edge *next;
            }E[maxe],*V[maxv];
            int tope=-1;
            void addedge(int x,int y,int z)
            {
                    E[++tope].np=y;
                    E[tope].val=z;
                    E[tope].next=V[x];
                    V[x]=&E[tope];
            }
            int q[maxv];
            int pnt[maxv];
            int fdis[maxv];
            pair<int,int> dpson[maxn];
            pair<int,int> dppnt[maxn];
            bool cent[maxv];
            int vsiz[maxv];
            void bfs(int rt)
            {
                    int now=rt;
                    Edge *ne;
                    int head=-1,tail=0;
                    q[0]=now;
                    while (head<tail)
                    {
                            now=q[++head];
                            for (ne=V[now];ne;ne=ne->next)
                            {
                                    if (ne->np==pnt[now])continue;
                                    pnt[ne->np]=now;
                                    fdis[ne->np]=ne->val;
                                    q[++tail]=ne->np;
                            }
                    }
                    for (int i=tail;i>=0;i--)
                    {
                            now=q[i];
                            if (cent[now])
                                    dpson[now]=make_pair(0,now);
                            else
                            {
                                    dpson[now]=make_pair(INF,INF);
                                    for (ne=V[now];ne;ne=ne->next)
                                    {
                                            if (ne->np==pnt[now])continue;
                                            dpson[now]=min(dpson[now],make_pair(dpson[ne->np].first+ne->val,dpson[ne->np].second));
                                    }
                            }
                    }
                    dppnt[rt]=dpson[rt];
                    for (int i=0;i<=tail;i++)
                    {
                            now=q[i];
                            if (cent[now])dppnt[now]=make_pair(0,now);
                            pair<int,int> pr=min(dpson[now],dppnt[now]);
                            for (ne=V[now];ne;ne=ne->next)
                            {
                                    if (ne->np==pnt[now])continue;
                                    dppnt[ne->np]=min(dppnt[ne->np],make_pair(pr.first+ne->val,pr.second));
                            }
                    }
                    for (int i=tail;i>=0;i--)
                    {
                            int now=q[i];
                            vsiz[now]=siz[now];
                            for (ne=V[now];ne;ne=ne->next)
                            {
                                    if (ne->np==pnt[now])continue;
                                    vsiz[now]-=siz[swim(ne->np,ne->val-1)];
                            }
                    }
                    vsiz[rt]+=n-siz[rt];
            }
            vector<int> pl;
            void main(vector<edge> &el,vector<int> &cl)
            {
                    pl.clear();
                    for (int i=0;i<el.size();i++)
                    {
                            addedge(el[i].x,el[i].y,el[i].v);
                            addedge(el[i].y,el[i].x,el[i].v);
                            pl.push_back(el[i].x);
                            pl.push_back(el[i].y);
                    }
                    sort(pl.begin(),pl.end());
                    pl.erase(unique(pl.begin(),pl.end()),pl.end());
                    int rt=pl[0];
                    for (int i=0;i<pl.size();i++)
                    {
                            if (depth[rt]>depth[pl[i]])rt=pl[i];
                            dppnt[pl[i]]=make_pair(INF,INF);
                    }
                    for (int i=0;i<cl.size();i++)
                            cent[cl[i]]=true;
                    bfs(rt);
                    for (int i=0;i<el.size();i++)
                    {
                            if (pnt[el[i].y]==el[i].x)
                                    swap(el[i].x,el[i].y);
                            pair<int,int> prx,pry;
                            prx=min(dpson[el[i].x],dppnt[el[i].x]);
                            pry=min(dpson[el[i].y],dppnt[el[i].y]);
                            if (prx.second==pry.second)
                            {
                                    el[i].dx=el[i].v;
                                    el[i].gx=prx.second;
                                    el[i].dy=-1;
                                    el[i].gy=-1;
                            }else
                            {
                                    el[i].gx=prx.second;
                                    el[i].gy=pry.second;
                                    el[i].dx=(el[i].v-1+pry.first-prx.first)/2;
                                    if (el[i].v-1+pry.first-prx.first<0)el[i].dx--;
                                    if ((el[i].v-1+pry.first-prx.first)%2 && el[i].gx<el[i].gy)
                                            el[i].dx++;
                                    el[i].dy=el[i].v-1-el[i].dx;
                            }
                    }
                    for (int i=0;i<pl.size();i++)
                    {
                            V[pl[i]]=0;
                            pnt[pl[i]]=0;
                            cent[pl[i]]=0;
                    }
                    tope=-1;
            }
    };
    int main()
    {
            //freopen("input.txt","r",stdin);
            int x,y;
            scanf("%d",&n);
            for (int i=1;i<n;i++)
            {
                    scanf("%d%d",&x,&y);
                    addedge(x,y);
                    addedge(y,x);
            }
            bfs(1);
            init_lca();
            dfs(1);
            scanf("%d",&m);
            int t;
            for (int i=0;i<m;i++)
            {
                    scanf("%d",&t);
                    if (t==1)
                    {
                            scanf("%d",&x);
                            printf("%d 
    ",n);
                            continue;
                    }
                    vector<int> cl;
                    for (int j=0;j<t;j++)
                    {
                            scanf("%d
    ",&ql[j].index);
                            ql[j].id=j;
                            cl.push_back(ql[j].index);
                            tot[ql[j].index]=0;
                    }
                    sort(ql,ql+t,cmp_pos);
                    vector<edge> el;
                    tops=-1;
                    memset(stack,0,sizeof(stack));
                    for (int j=0;j<t;j++)
                    {
                            if (tops==-1)
                            {
                                    stack[++tops]=ql[j].index;
                            }else
                            {
                                    int a=lca(stack[tops],ql[j].index);
                                    if (a==stack[tops])
                                    {
                                            stack[++tops]=ql[j].index;
                                            continue;
                                    }else
                                    {
                                            int a=lca(stack[tops],ql[j].index);;
                                            while (tops && depth[a]<depth[stack[tops-1]])
                                            {
                                                    el.push_back(edge(stack[tops],stack[tops-1],dis(stack[tops],stack[tops-1])));
                                                    tops--;
                                            }
                                            el.push_back(edge(a,stack[tops],dis(a,stack[tops])));
                                            tops--;
                                            stack[tops+1]=a;tops++;
                                            if (stack[tops]==stack[tops-1])tops--;
                                            stack[++tops]=ql[j].index;
                                    }
                            }
                    }
                    while (tops)
                    {
                            el.push_back(edge(stack[tops],stack[tops-1],dis(stack[tops],stack[tops-1])));
                            tops--;
                    }
                    //for (int j=0;j<el.size();j++)printf("edge:%d %d %d
    ",el[j].x,el[j].y,el[j].v);
                    task2::main(el,cl);
                    for (int j=0;j<el.size();j++)
                    {
                            assert(depth[el[j].x]>depth[el[j].y]);
                            int t=swim(el[j].x,depth[el[j].x]-depth[el[j].y]-1);
                            if (el[j].gx==-1)
                            {
                                    tot[el[j].gy]+=siz[t]-siz[el[j].x];
                            }else if (el[j].gy==-1)
                            {
                                    tot[el[j].gx]+=siz[t]-siz[el[j].x];
                            }else
                            {
                                    int d=swim(el[j].x,el[j].dx);
                                    tot[el[j].gx]+=siz[d]-siz[el[j].x];
                                    tot[el[j].gy]+=siz[t]-siz[d];
                            }
                    }
                    for (int j=0;j<task2::pl.size();j++)
                    {
                            pair<int,int> pr=min(task2::dpson[task2::pl[j]],task2::dppnt[task2::pl[j]]);
                            tot[pr.second]+=task2::vsiz[task2::pl[j]];
                    }
                    sort(ql,ql+t,cmp_id);
                    for (int j=0;j<t;j++)
                            printf("%d ",tot[ql[j].index]);
                    printf("
    ");
            }
    }
  • 相关阅读:
    PHP基础1
    U2-Net网络学习笔记(记录)
    C++贪吃蛇游戏
    实习期间学习基础学习整理
    week 2020.1.10-2020.1.15
    week 2021.1.04-2021.1.08
    week 2020.12.21-2020.12.31
    周记 week 2020-12.14-12.18
    几种读取图片和标签的方法
    图像风格转换(Style Transfer | 风格迁移综述)
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4501959.html
Copyright © 2011-2022 走看看