[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 }