「BZOJ3572」[HNOI2014]世界树

建出虚树

两遍dp求出虚树上的各点被哪个点管辖

再对虚树上的每一条边计算贡献

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=300010,P=25,oo=2e9;
  4 int n,m,q,a[N];
  5 int fa[N][P],dep[N],id[N],siz[N],dfn;
  6 int ans[N],b[N],c[N],f[N],d[N],w[N];
  7 struct Edge{
  8     int from,to,v,next;
  9     Edge(int _from=0,int _to=0,int _v=0,int _next=0):from(_from),to(_to),v(_v),next(_next){}
 10 }edge[N<<1];
 11 int edge_tot,last[N];
 12 inline void add_edge(int f,int t,int vv){edge[++edge_tot]=Edge(f,t,vv,last[f]),last[f]=edge_tot;return;}
 13 int cmp(int x,int y){return id[x]<id[y];}
 14 void dfs(int k,int father,int d){
 15     fa[k][0]=father,dep[k]=d,id[k]=++dfn,siz[k]=1;
 16     for(int i=last[k];i;i=edge[i].next){
 17         if(edge[i].to==father) continue;
 18         dfs(edge[i].to,k,d+1);
 19         siz[k]+=siz[edge[i].to];
 20     }
 21     return;
 22 }
 23 int getlca(int x,int y){
 24     if(dep[x]<dep[y]) swap(x,y);
 25     for(int i=19;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
 26     if(x==y) return x;
 27     for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 28     return fa[x][0];
 29 }
 30 inline int getson(int x,int y){
 31     for(int i=19;i>=0;i--) if(dep[fa[y][i]]>dep[x]) y=fa[y][i];
 32     return y;
 33 }
 34 int sta[N],top;
 35 inline void build(){
 36     int lca;
 37     if(f[1]!=1) sta[top++]=1;
 38     for(int i=1;i<=m;i++){
 39         while(1){
 40             if(!top) break;
 41             lca=getlca(sta[top-1],a[i]);
 42             if(lca==sta[top-1]) break;
 43             else{
 44                 top--;
 45                 if(id[sta[top-1]]>=id[lca]){
 46                     add_edge(sta[top-1],sta[top],siz[getson(sta[top-1],sta[top])]-siz[sta[top]]);
 47                 }else{
 48                     add_edge(lca,sta[top],siz[getson(lca,sta[top])]-siz[sta[top]]);
 49                     sta[top++]=lca;
 50                     break;
 51                 }
 52             }
 53         }
 54         sta[top++]=a[i];
 55     }
 56     while(top>=2){top--;add_edge(sta[top-1],sta[top],siz[getson(sta[top-1],sta[top])]-siz[sta[top]]);}
 57     return;
 58 }
 59 void dfs_dp1(int k,int father){
 60     c[++dfn]=k,w[k]=siz[k];
 61     for(int i=last[k];i;i=edge[i].next){
 62         if(edge[i].to==father) continue;
 63         w[k]-=siz[edge[i].to]+edge[i].v;
 64         dfs_dp1(edge[i].to,k);
 65         if(d[k]>d[edge[i].to]+dep[edge[i].to]-dep[k]) d[k]=d[edge[i].to]+dep[edge[i].to]-dep[k],f[k]=f[edge[i].to];
 66         else if(d[k]==d[edge[i].to]+dep[edge[i].to]-dep[k]&&f[edge[i].to]<f[k]) f[k]=f[edge[i].to];
 67     }
 68     return;
 69 }
 70 void dfs_dp2(int k,int father){
 71     for(int i=last[k];i;i=edge[i].next){
 72         if(edge[i].to==father) continue;
 73         if(d[edge[i].to]>d[k]+dep[edge[i].to]-dep[k]) d[edge[i].to]=d[k]+dep[edge[i].to]-dep[k],f[edge[i].to]=f[k];
 74         else if(d[edge[i].to]==d[k]+dep[edge[i].to]-dep[k]&&f[edge[i].to]>f[k]) f[edge[i].to]=f[k];
 75         dfs_dp2(edge[i].to,k);
 76     }
 77     return;
 78 }
 79 inline void solve(int k){
 80     int t1=edge[k].from,t2=edge[k].to,nxt;
 81     if(f[t1]==f[t2]){ans[f[t1]]+=edge[k].v;return;}
 82     int mid=t2;
 83     for(int i=19;i>=0;i--){
 84         nxt=fa[mid][i];
 85         if(id[nxt]<id[t1]) continue;
 86         if(d[t1]+dep[nxt]-dep[t1]>d[t2]+dep[t2]-dep[nxt]||(d[t1]+dep[nxt]-dep[t1]==d[t2]+dep[t2]-dep[nxt])&&f[t2]<f[t1]) mid=nxt;
 87     }
 88     ans[f[t1]]+=siz[getson(t1,mid)]-siz[mid];
 89     ans[f[t2]]+=siz[mid]-siz[t2];
 90     return;
 91 }
 92 inline void clear(){
 93     for(int i=1;i<=dfn;i++) last[c[i]]=f[c[i]]=ans[c[i]]=w[c[i]]=0,d[c[i]]=oo;
 94     edge_tot=dfn=top=0;
 95     return;
 96 }
 97 void query(){
 98     int t1,t2;
 99     scanf("%d",&m);
100     for(int i=1;i<=m;i++) scanf("%d",&a[i]),b[i]=a[i],f[a[i]]=a[i],d[a[i]]=0;
101     sort(a+1,a+m+1,cmp);
102     build();
103     dfs_dp1(1,0);dfs_dp2(1,0);
104     for(int i=1;i<=dfn;i++) ans[f[c[i]]]+=w[c[i]];
105     for(int i=1;i<=edge_tot;i++)
106         solve(i);
107     for(int i=1;i<=m;i++) printf("%d ",ans[b[i]]);
108     printf("\n");
109     clear();
110     return;
111 }
112 int main(){
113     int t1,t2;
114     scanf("%d",&n);
115     for(int i=1;i<n;i++){
116         scanf("%d%d",&t1,&t2);
117         add_edge(t1,t2,0);add_edge(t2,t1,0);
118     }
119     dfs(1,0,1);
120     for(int i=1;i<=19;i++)
121         for(int j=1;j<=n;j++)
122             fa[j][i]=fa[fa[j][i-1]][i-1];
123     memset(last,0,sizeof(last));memset(d,127/2,sizeof(d));
124     edge_tot=dfn=0;
125     scanf("%d",&q);
126     while(q--) query();
127     return 0;
128 }

 

posted @ 2018-03-08 13:23  Cupcake  阅读(128)  评论(0编辑  收藏  举报