【洛谷】世界树-虚数/树形DP

原创 2018年04月15日 20:03:41

传送门:洛谷-世界树


题意

世界树的形态可以用一个数学模型来描述:世界树中有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年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。


数据范围

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


题解

先建一棵树模拟一下,就会发现对于每个点,如果它的子树里都没有议事处,那么肯定归它管,对于它上面的,找到距离恰为和祖先中第一个议事处距离的一半的,判一下标号大小就好了。
那么结合m的提示,我们对于每一次询问建一颗虚树。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,x,y,h[N],tot,Q,m,dfn,flor;
int head[N],to[N<<1],nxt[N<<1],a[N],b[N],c[N],top;
int d[N],ans[N],f[N][20],sz[N],rem[N];
int id[N],bel[N],s[N],mx; 

inline int read()
{
    char ch=getchar();int x=0,t=1;
    while(ch<'0' || ch>'9') {if(ch=='-') t=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*t;
}

inline bool cmp(int x,int y)
{
    return id[x]<id[y];
}

inline int lca(int x,int y)
{
   if(d[x]>d[y]) swap(x,y);
   int t=d[y]-d[x];
   for(register int i=0;(1LL<<i)<=t;i++){
       if(t&(1LL<<i)) y=f[y][i];
   }
   for(register int i=flor;i>=0;i--){
      if(f[x][i]!=f[y][i]){
         x=f[x][i];y=f[y][i];
      }
   }
   if(x!=y){
    return f[x][0];
   }else{
    return x;
   }
}

inline int dis(int x,int y)
{
    return (d[x]+d[y]-2*(d[lca(x,y)])); 
}

inline void lk(int u,int v)
{
    to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}

inline void dfs(int x,int fa)
{
    int e;sz[x]=1;id[x]=++dfn;
    for(register int i=1;(1LL<<i)<=d[x];i++){
       f[x][i]=f[f[x][i-1]][i-1]; 
    } 
    for(register int i=head[x];i;i=nxt[i]){
        if(to[i]==fa) continue;
        e=to[i];d[e]=d[x]+1;
        f[e][0]=x;
        dfs(e,x);
        sz[x]+=sz[e];
    }
    mx=max(mx,d[x]);
}

inline void df(int x)
{
    c[++dfn]=x;rem[x]=sz[x];int e;
    for(register int i=head[x];i;i=nxt[i]){
        e=to[i];
        df(e);
        if(!bel[e]) continue;
        int t1=dis(bel[e],x),t2=dis(bel[x],x);
        if(((t1==t2)&&bel[e]<bel[x])||(t1<t2)||(!bel[x])) bel[x]=bel[e];
    }
}

inline void dff(int x)
{
    int e;
    for(register int i=head[x];i;i=nxt[i]){
        e=to[i];
        int t1=dis(bel[e],e),t2=dis(bel[x],e);
        if(((t1==t2)&&bel[x]<bel[e])||(t2<t1)||!bel[e]) bel[e]=bel[x];
        dff(e); 
    }
}

inline void solve(int a,int b)
{
     int ct=b,x=b;
     for(register int i=flor;i>=0;i--){
        if(d[f[x][i]]>d[a]){
            x=f[x][i];
        }
     }  
     rem[a]-=sz[x];
     if(bel[a]==bel[b]){
        ans[bel[a]]+=sz[x]-sz[b];
     }else{
        int e;
        for(register int i=flor;i>=0;i--){
            e=f[ct][i];
            if(d[e]<=d[a]) continue;
            int t1=dis(bel[a],e),t2=dis(bel[b],e);
            if(((t1==t2)&&(bel[b]<bel[a]))||(t1>t2)) ct=e;
        }
        ans[bel[a]]+=(sz[x]-sz[ct]);
        ans[bel[b]]+=(sz[ct]-sz[b]);
     }
}

int main(){
    n=read();
    for(register int i=1;i<n;i++){
        int u=read(),v=read();
        lk(u,v);lk(v,u);
    }
    dfs(1,0);
    flor=(int)(log(mx)/log(2));
    if((1LL<<flor)<mx) flor++;
    memset(head,0,sizeof(head));
    Q=read();
    while(Q--){
        dfn=0;top=0;tot=0;
        m=read();
        for(register int i=1;i<=m;i++){
            a[i]=read();b[i]=a[i];
            bel[a[i]]=a[i];
        }
        sort(a+1,a+m+1,cmp);
        if(bel[1]!=1) s[++top]=1;
        for(register int i=1;i<=m;i++){
           int t=a[i],p=0;
           while(top>0){
              p=lca(s[top],t);
              if(top>1 && d[p]<d[s[top-1]]){
                lk(s[top-1],s[top]);top--;
              }else if(d[p]<d[s[top]]){
                lk(p,s[top]);top--;break;
              }else break;
           }
           if(s[top]!=p) s[++top]=p;
           s[++top]=t;
         }
         while(top>1){lk(s[top-1],s[top]);top--;}
           df(1);dff(1);
           for(register int i=1;i<=dfn;i++){
            for(register int j=head[c[i]];j;j=nxt[j]){
                solve(c[i],to[j]);
            }
           }
           for(register int i=1;i<=dfn;i++) 
             ans[bel[c[i]]]+=rem[c[i]];
           for(register int i=1;i<=m;i++) printf("%d ",ans[b[i]]);
           printf("\n");
           for(register int i=1;i<=dfn;i++){
              ans[c[i]]=bel[c[i]]=rem[c[i]]=head[c[i]]=0;
           }
        } 
        return 0;
}

ps:代码参照hzwer

版权声明:侵删,转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/79952494

树的重心——树形dp

树的重心(质心):对于一颗n个节点的无根树,找到一个点,使得把树变成以该节点为根的有根树时,最大节点数最少。换句话说,删除这个节点后最大连通块(一定是树)的节点数最少。 PS:首先要知道什么是树的重...
  • qq_33850438
  • qq_33850438
  • 2016-02-22 02:37:26
  • 622

动态规划-树形dp总结

一.简单的从下到上和从上到下的统计 1.      dp[u]表示以u为根的一共有多少个节点.可以用来求重心. 2.      每个点出发能够走得最远的长度.dpm[u], dps[u]用来保存u...
  • u013625492
  • u013625492
  • 2015-06-17 17:02:56
  • 1449

洛谷2279消防局的设立

题目描述2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地。起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结...
  • KenxHe
  • KenxHe
  • 2016-11-03 21:49:34
  • 237

树形dp题集之树的直径

【codeforces 592D】 #include using namespace std; #define inf 130000 vectoradj[inf]; int vis[inf]; in...
  • saragrean
  • saragrean
  • 2015-11-06 22:29:44
  • 510

Trie树练习题 启发式合并

练习题 Time Limit: 2 Sec  Memory Limit: 256 MB Description   有一棵树,每一个点有一个权值,对于每一个点,求出子树路径最大异或和(就是这条路上所...
  • youhavepeople
  • youhavepeople
  • 2017-09-27 17:24:59
  • 208

bzoj1304&&洛谷3155,树形DP

题目 首先,可以发现选哪个点为根都一样(然而并不容易发现)。 接下来,设g0[x]为使以x为根的子树中只剩下颜色为0的叶节点未被覆盖,需要的染色数,g1[x]为使以x为根的子树中只剩下颜色为1的叶...
  • zxin__
  • zxin__
  • 2017-01-24 20:25:07
  • 238

树形DP求树的直径

hdu4607
  • u012859437
  • u012859437
  • 2014-05-10 20:09:59
  • 1168

洛谷P1270 树形DP

题目描述 经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动。艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室。Peer知道每个展室里藏画的数...
  • fan233
  • fan233
  • 2017-11-10 16:05:53
  • 94

树形动态规划(树形DP)入门问题—初探 & 训练

树形DP入门 poj 2342 Anniversary party   先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的...
  • txl16211
  • txl16211
  • 2015-04-29 22:40:03
  • 11014

【洛谷2458】【SDOI2006】保安站岗(树形DP)

树形DP,一个经典套路
  • white945
  • white945
  • 2017-10-19 09:34:17
  • 82
收藏助手
不良信息举报
您举报文章:【洛谷】世界树-虚数/树形DP
举报原因:
原因补充:

(最多只允许输入30个字)