虚树入门!世界树!

虚树,顾名思义,就是建一颗虚假的树

这个树和原树的区别就是,他只保留了一些询问的必要节点,和必要节点之间的lca。这样能让这颗虚树具有树的性质,且不改变点之间的相对位置。

然后这颗虚树的节点数最多只有询问点数*2个,这样可以大幅度降低单词询问的复杂度。然后通过树形dp来解决问题。

题目来源:BZOJ3572

(其实这道题不适合用来入门,树形dp的部分比较难)

世界树啊    这个题我感觉很麻烦   难点不在虚树,而是树形dp啊

我大概说一下做法吧

1、手动把1这个节点加入虚树中,成为虚树的根(判断一下询问点有没有1)。(因为这题需要用到深度啊,子树大小啊之类的,所以根经常变的话会很难做)

2、树形dp吧,对于虚树上每个非询问点,找到一个和他自己最近的节点。(这里注意一下。。我是求错了几次。。找了半天)。。

3、然后对虚树上相邻的两个节点之间的边进行二分,找到距离的分界点。

4、把每个节点的贡献加到离自己最近的节点上。(注意有一些没有统计到的节点也要统计进去)(具体是用子树大小减减减)

代码如下:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<vector>
  4 #include<algorithm>
  5 using namespace std;
  6 ///////////--虚树模板--///////////////////
  7 //传入树的一个子集,若以按dfs序排好直接调用build_vtree
  8 //否则调用vsort
  9 //复杂度O( nlog(n) ) n是虚树的大小
 10  
 11 #define N 330000
 12 #define LN 21
 13  
 14 ////////////--标准建邻接表--/////////////
 15 struct node
 16 {
 17     int to,next;
 18 } edge[2*N];
 19  
 20 int cnt,pre[N];
 21  
 22 void creat()
 23 {
 24     memset(pre,-1,sizeof(pre));
 25     cnt=0;
 26 }
 27  
 28 void add_edge(int u,int v)
 29 {
 30     edge[cnt].to = v;
 31     edge[cnt].next = pre[u];
 32     pre[u] = cnt++;
 33 }
 34 //////////////////////////////////////
 35  
 36 int deep[N];//记录每个点的深度
 37 int order[N];//记录每个点的访问次序
 38 int sz[N];
 39 int indx=0;
 40  
 41 struct Lca_Online
 42 {
 43     int _n;
 44  
 45     int dp[N][LN];
 46  
 47     void _dfs(int s,int fa,int dd)
 48     {
 49         sz[s]=1;
 50         deep[s] = dd;
 51         order[s] = ++indx;
 52         for(int p=pre[s]; p!=-1; p=edge[p].next)
 53         {
 54             int v = edge[p].to;
 55             if(v == fa)
 56                 continue;
 57             _dfs(v,s,dd+1);
 58             sz[s]+=sz[v];
 59             dp[v][0] = s;
 60         }
 61     }
 62  
 63     void _init()
 64     {
 65         for(int j=1; (1<<j)<=_n; j++)
 66         {
 67             for(int i=1; i<=_n; i++)
 68             {
 69                 if(dp[i][j-1]!=-1)
 70                     dp[i][j] = dp[ dp[i][j-1] ][j-1];
 71             }
 72         }
 73     }
 74     void lca_init(int n)
 75     {
 76         _n = n;
 77         memset(dp,-1,sizeof(dp));
 78         //_dfs(firstid,-1,0);
 79         indx = 0;
 80         _dfs(1,-1,0);
 81         _init();
 82     }
 83  
 84     int lca_query(int a,int b)
 85     {
 86         if(deep[a]>deep[b])
 87             swap(a,b);
 88         //调整b到a的同一高度
 89         for(int i=LN-1; deep[b]>deep[a]; i--)
 90             if(deep[b]-(1<<i) >= deep[a])
 91                 b = dp[b][i];
 92         if(a == b)
 93             return a;
 94         for(int i=LN-1; i>=0; i--)
 95         {
 96             if(dp[a][i]!=dp[b][i])
 97                 a = dp[a][i],b = dp[b][i];
 98         }
 99         return dp[a][0];
100     }
101 } lca;
102  
103 int stk[N],top;
104 int mark[N];//标示虚树上的点是否是无用点
105 vector<int>tree[N];//存边
106 vector<int>treew[N];//存权
107  
108 void tree_add(int u,int v,int w)
109 {
110     tree[u].push_back(v);
111     tree[v].push_back(u);
112     treew[u].push_back(w);
113     treew[v].push_back(w);
114 }
115 int dis(int a,int b)
116 {
117     return deep[a]+deep[b]-2*deep[lca.lca_query(a,b)];
118 }
119  
120 int belong[N],h[N],ans[N],c[N],f[N];
121  
122 void fz(int fa,int s)
123 {
124     int x=s,low=s;
125     for(int i=20; i>=0; i--)
126         if(lca.dp[low][i]!=-1)
127             if(deep[lca.dp[low][i]]>deep[fa])
128                 low=lca.dp[low][i];
129     c[fa]-=sz[low];
130     if(belong[fa]==belong[s])
131     {
132         f[belong[fa]]+=sz[low]-sz[s];
133         return ;
134     }
135     x=s;
136     for(int i=20; i>=0; i--)
137         if(lca.dp[x][i]!=-1&&deep[lca.dp[x][i]]>=deep[low])
138             if(dis(belong[fa],lca.dp[x][i])>dis(lca.dp[x][i],belong[s]))
139                 x=lca.dp[x][i];
140     if(belong[s]<belong[fa]&&dis(belong[fa],lca.dp[x][0])==dis(belong[s],lca.dp[x][0])&&lca.dp[x][0]!=fa)
141     {
142         x=lca.dp[x][0];
143         f[belong[fa]]+=sz[low]-sz[x];
144         f[belong[s]]+=sz[x]-sz[s];
145     }
146     else
147     {
148         f[belong[fa]]+=sz[low]-sz[x];
149         f[belong[s]]+=sz[x]-sz[s];
150     }
151 }
152  
153 void dfs2(int now,int fa)
154 {
155     c[now]=f[now]=belong[now]=mark[now]=ans[now]=0;
156     for(int i=0; i<tree[now].size(); i++)
157     {
158         if(tree[now][i]==fa)
159             continue;
160         dfs2(tree[now][i],now);
161     }
162     tree[now].clear();
163     treew[now].clear();
164 }
165 void dfs1(int now,int fa)
166 {
167     c[now]=sz[now];
168     for(int i=0; i<tree[now].size(); i++)
169     {
170         if(tree[now][i]==fa)
171             continue;
172         dfs1(tree[now][i],now);
173         if(mark[now]==0)
174         {
175             int t=belong[tree[now][i]];
176             int t1=dis(now,t),t2=dis(now,belong[now]);
177             if(!belong[now]||t1<t2||t1==t2&&t<belong[now])
178                 belong[now]=t;
179         }
180     }
181 }
182 void dfs3(int now,int fa)
183 {
184     if(fa!=0&&mark[now]==0)
185     {
186         int t=belong[fa];
187         int t1=dis(t,now),t2=dis(now,belong[now]);
188         if(!belong[now]||t1<t2||t1==t2&&t<belong[now])
189             belong[now]=t;
190     }
191     for(int i=0; i<tree[now].size(); i++)
192         if(tree[now][i]!=fa)
193         {
194             dfs3(tree[now][i],now);
195  
196         }
197 }
198 void dfss(int now,int fa)
199 {
200     for(int i=0; i<tree[now].size(); i++)
201         if(tree[now][i]!=fa)
202         {fz(now,tree[now][i]);
203             dfss(tree[now][i],now);
204  
205         }
206 }
207 void dfsss(int now,int fa)
208 {
209     for(int i=0; i<tree[now].size(); i++)
210         if(tree[now][i]!=fa)
211             dfsss(tree[now][i],now);
212     ans[belong[now]]+=c[now]+f[now];
213 }
214  
215 //使用前调用 lca.lca_init(n); 初始化
216 //返回虚树根节点,虚树的边默认为原树上两点的距离
217 int build_vtree(int vp[],int vn)//传入按dfs序数组,以及长度(要自己写按dfs排序的数组)
218 {
219     if(vn == 0)
220         return -1;
221     top = 0;
222     for(int i=0; i<vn; i++)
223         belong[vp[i]]=vp[i];
224     int i=0;
225     if(belong[1]==1)
226     {
227         stk[top++] = vp[0];
228         tree[ vp[0] ].clear();
229         treew[ vp[0] ].clear();
230         mark[ vp[0] ]=1;
231         i++;
232     }
233     else
234     {
235         stk[top++] = 1;
236         tree[1].clear();
237         treew[1].clear();
238     }
239     for(; i<vn; i++)
240     {
241         int v = vp[i];
242  
243         int plca = lca.lca_query(stk[top-1], v);//最近公共祖先
244         if(plca == stk[top-1]) ;//不处理
245         else
246         {
247             int pos=top-1;
248             while(pos>=0 && deep[ stk[pos] ]>deep[plca])
249                 pos--;
250             pos++;
251             for(int j=pos; j<top-1; j++)
252             {
253                 tree_add(stk[j],stk[j+1],deep[stk[j+1]]-deep[stk[j]]);
254             }
255             int prepos = stk[pos];
256             if(pos == 0)
257             {
258                 tree[plca].clear(),treew[plca].clear(),stk[0]=plca,top=1;
259                 mark[plca] = 0;
260             }
261             else if(stk[pos-1] != plca)
262             {
263                 tree[plca].clear(),treew[plca].clear(),stk[pos]=plca,top=pos+1;
264                 mark[plca] = 0;
265             }
266             else
267                 top = pos;
268             tree_add(prepos,plca,deep[prepos]-deep[plca]);
269  
270         }
271         tree[v].clear();
272         treew[v].clear();
273         stk[top++] = v;
274         mark[v] = 1;
275     }
276     for(i=0; i<top-1; i++)
277     {
278         tree_add(stk[i], stk[i+1], deep[stk[i+1]]-deep[stk[i]]);
279     }
280     dfs1(1,0);
281     dfs3(1,0);
282     dfss(1,0);
283     dfsss(1,0);
284     return 1;
285 }
286  
287 //////////////--先排序,再建虚树--//////////////////////
288 struct vnode
289 {
290     int order,id;
291 } vg[N];
292 int vcmp(vnode t1,vnode t2)
293 {
294     return t1.order<t2.order;
295 }
296 int b[N];
297 int vsort(int vp[],int vn)//传入未排序的数组,以及长度.
298 {
299     for(int i=0; i<vn; i++)
300         b[i]=vg[i].id = vp[i],vg[i].order = order[ vp[i] ];
301     sort(vg,vg+vn,vcmp);
302     for(int i=0; i<vn; i++)
303         vp[i]=vg[i].id;
304     build_vtree(vp, vn);
305     for(int i=0; i<vn; i++)
306         printf("%d ",ans[b[i]]);
307     puts("");
308     dfs2(1,0);
309     return 1;
310 }
311 int main()
312 {
313     int n;
314     scanf("%d",&n);
315     creat();
316     for(int i=1,x,y; i<n; i++)
317     {
318         scanf("%d%d",&x,&y);
319         add_edge(x,y);
320         add_edge(y,x);
321     }
322     int Q;
323     scanf("%d",&Q);
324     lca.lca_init(n);
325     for(int q=1; q<=Q; q++)
326     {
327         int m;
328         scanf("%d",&m);
329         for(int i=0; i<m; i++)
330             scanf("%d",h+i);
331         vsort(h,m);
332     }
333 }
View Code
原文地址:https://www.cnblogs.com/xseventh/p/8585735.html