[HNOI2014][bzoj3572] 世界树 [虚树+dp]

题面:

传送门

思路:

一道虚树的好题,是很多虚树博客的入门题目

但是我认为这道题目出的难点和亮点不在于虚树,而在于建出虚树以后dp的思路与实现

 

下文中为方便描述,用势力范围来表示一个“议事处”管辖的节点集合

 

首先,看完题目以后一个直观的感受,就是我去考虑两个询问点之间,哪些点属于谁的势力范围,然后这样

这是个类似暴力的东西

那树上路径的中点怎么求?可以lca求出距离以后倍增

但是现在问题来了,虚树上的节点有的是询问点,有的只是询问点的lca,并不参与询问,怎么解决这个问题呢?

而且在那个初始想法中,有一些路径是势必会重复的,又怎么解决?

一个直观的想法就是把一堆路径询问简化掉

我们发现一个点终究只能属于一个询问点的势力范围,那么一条边上的节点同理

所以我们可以把重复经过同一条边的询问拆到每条虚树边上,然后对于每条虚树边来考虑解题

 

显然,虚树边分为两种:两边的虚树点被同一个节点控制的,或者两端被不同节点控制的

对于两端被同一个询问点控制的边,显然这条虚树边上的所有的点的所有子树都被这个点控制

另一种情况则是在中间有一个分界线,界线一边的点与它们的子树被那一边的端点的“主人”控制

那么也就是说,我们只需要处理出虚树上的每一个节点被哪个询问点控制,然后对于上面的两种情况分别考虑、统计答案就行了

那么怎么处理这个控制关系呢?

 

我们做两次dfs

第一次,我们求出某个虚树节点的所有儿子中离它最近的控制点

第二次,则用父亲的控制点(和儿子不在同一个子树中)来更新儿子的控制点

 

dp的时候则是依然用倍增来实现跳到分界点上

两个点之间的距离则可以用lca实现

 

大概就是这样了,更具体的内容可以参考代码

 

Code:

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #define ll long long
  6 #define inf 1e9
  7 using namespace std;
  8 inline int read(){
  9     int re=0,flag=1;char ch=getchar();
 10     while(ch>'9'||ch<'0'){
 11         if(ch=='-') flag=-1;
 12         ch=getchar();
 13     }
 14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
 15     return re*flag;
 16 }
 17 int n,dep[300010],siz[300010],st[300010][20],dfn[300010],clk;
 18 struct graph{
 19     int first[300010],cnt;
 20     struct edge{
 21         int to,next;
 22     }a[600010];
 23     inline void add(int u,int v){
 24         if(u==v) return;
 25         a[++cnt]=(edge){v,first[u]};first[u]=cnt;
 26     }
 27     graph(){
 28         memset(first,-1,sizeof(first));cnt=0;
 29     }
 30     void init(){cnt=0;}
 31 }G,g;
 32 void dfs(int u,int f){
 33 //  cout<<"begin dfs "<<u<<endl;
 34     int i,v;
 35     dep[u]=dep[f]+1;st[u][0]=f;dfn[u]=++clk;siz[u]=1;
 36     for(i=G.first[u];~i;i=G.a[i].next){
 37         v=G.a[i].to;
 38         if(v==f) continue;
 39         dfs(v,u);siz[u]+=siz[v];
 40     }
 41 //  cout<<"end of dfs "<<u<<ends<<dep[u]<<ends<<siz[u]<<endl;
 42     return;
 43 }
 44 void ST(){
 45     int i,j;
 46     for(j=1;j<=19;j++) for(i=1;i<=n;i++) st[i][j]=st[st[i][j-1]][j-1];
 47 }
 48 int lca(int l,int r){
 49     if(dep[l]>dep[r]) swap(l,r);
 50     int i;
 51     for(i=19;i>=0;i--) if(dep[st[r][i]]>=dep[l]) r=st[r][i];
 52     if(l==r) return l;
 53     for(i=19;i>=0;i--)
 54         if(st[r][i]!=st[l][i]){
 55             r=st[r][i];
 56             l=st[l][i];
 57         }
 58     return st[l][0];
 59 }
 60 int q[300010],ans[300010],num[300010],s[300010],top;
 61 bool vis[300010];
 62 bool cmp1(int l,int r){
 63     return dfn[l]<dfn[r];
 64 }
 65 bool cmp2(int l,int r){
 66     return num[l]<num[r];
 67 }
 68 int minn[300010],belong[300010],sur[300010];
 69 int dis(int l,int r){return dep[l]+dep[r]-2*dep[lca(l,r)];}
 70 void dfs1(int u){
 71     int i,v,d1,d2;belong[u]=(vis[u]?u:0);sur[u]=siz[u];
 72     for(i=g.first[u];~i;i=g.a[i].next){
 73         v=g.a[i].to;dfs1(v);
 74         d1=dep[belong[v]]-dep[u];d2=(belong[u]?dep[belong[u]]-dep[u]:inf);
 75         if(d1<d2||(d1==d2&&belong[v]<belong[u])) belong[u]=belong[v];
 76     }
 77 }
 78 void dfs2(int u){
 79     int i,v,d1,d2;
 80     for(i=g.first[u];~i;i=g.a[i].next){
 81         v=g.a[i].to;d1=dis(belong[u],v);d2=dis(belong[v],v);
 82         if(d1<d2||(d1==d2&&belong[u]<belong[v])) belong[v]=belong[u];
 83         dfs2(v);
 84     }
 85 }
 86 void dp(int u){
 87 //  cout<<"enter dp "<<u<<ends<<belong[u]<<endl;
 88     int i,v,d1,d2,mid,tv,j,tmp;
 89     for(i=g.first[u];~i;i=g.a[i].next){
 90         v=g.a[i].to;g.first[u]=g.a[i].next;mid=tv=v;
 91 //      cout<<"going to "<<v<<endl;
 92         dp(v);
 93         for(j=19;j>=0;j--) if(dep[st[tv][j]]>dep[u]) tv=st[tv][j];
 94         sur[u]-=siz[tv];
 95 //      cout<<"edge up to "<<tv<<endl;
 96         if(belong[u]==belong[v]){
 97             ans[belong[u]]+=siz[tv]-siz[v];continue;
 98         }
 99         for(j=19;j>=0;j--){
100             tmp=st[mid][j];if(dep[tmp]<=dep[u]) continue;
101             d1=dis(tmp,belong[v]);d2=dis(tmp,belong[u]);
102             if(d1<d2||(d1==d2&&belong[v]<belong[u])) mid=tmp;
103         }
104 //      cout<<"********diff edge "<<mid<<endl;
105         ans[belong[u]]+=siz[tv]-siz[mid];
106         ans[belong[v]]+=siz[mid]-siz[v];
107     }
108 //  cout<<"end of dp "<<u<<ends<<sur[u]<<endl;
109     ans[belong[u]]+=sur[u];
110 }
111 void solve(){
112 //  cout<<"*************************enter solve\n";
113     int m=read(),i,grand;
114     for(i=1;i<=m;i++) q[i]=read(),num[q[i]]=i,vis[q[i]]=1;;
115     sort(q+1,q+m+1,cmp1);top=0;g.init();s[++top]=1;
116     for(i=1;i<=m;i++){
117 //      if(!top){s[++top]=q[i];continue;}
118         grand=lca(s[top],q[i]);
119         while(1){
120             if(dep[s[top-1]]<=dep[grand]){
121                 g.add(grand,s[top--]);
122                 if(s[top]!=grand) s[++top]=grand;
123                 break;
124             }
125             g.add(s[top-1],s[top]);top--;
126         }
127         if(s[top]!=q[i]) s[++top]=q[i];
128     }
129     while(--top>=1) g.add(s[top],s[top+1]); 
130     dfs1(s[1]);dfs2(s[1]);dp(s[1]);
131     sort(q+1,q+m+1,cmp2);
132 //  for(i=1;i<=m;i++) cout<<q[i]<<ends;cout<<endl;
133     for(i=1;i<=m;i++) vis[q[i]]=0,num[q[i]]=inf,printf("%d ",ans[q[i]]),ans[q[i]]=0;
134     puts("");
135 }
136 int main(){
137 //  cout<<"begin\n";
138     int i,t1,t2;
139     n=read();memset(num,0x3f,sizeof(num));
140 //  cout<<"input n "<<n<<endl;
141     for(i=1;i<n;i++){
142         t1=read();t2=read();
143         G.add(t1,t2);G.add(t2,t1);
144     }
145 //  cout<<"input of tree end\n";
146     dfs(1,0);ST();
147     int Q=read();
148     for(i=1;i<=Q;i++) solve();
149 }

 

posted @ 2018-03-14 21:12  dedicatus545  阅读(262)  评论(0编辑  收藏  举报