luogu3233 世界树 (虚树)

反正肯定要建虚树,考虑建完之后怎么做

先随便dp一下算出来距离某点最近的询问点mi[x](因为有的虚树上的点它不是询问点嘛)

那我们对于某条链x到fa[x]上的非虚树上的点(包括他们的非虚树上的孩子),要么把它分给mi[x],要么分给mi[fa[x]]

我找到这个中间点以后,在原树上倍增跳过去,算他的size

这个分法是以$\frac{len[mi[x]]+len[x]+len[mi[fa[x]]]}{2}$再加加减减一些细节决定的(len[x]表示x到fa[x]的链的长度)

除此之外,每个在虚树上的点x(以及它不在虚树上的孩子),都归属于mi[x]

  1 #include<bits/stdc++.h>
  2 #define mp make_pair
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 typedef unsigned long long ull;
  7 typedef pair<int,int> pa;
  8 const int maxn=3e5+10,inf=1e9;
  9
 10 inline ll rd(){
 11     ll x=0;char c=getchar();int neg=1;
 12     while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();}
 13     while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
 14     return x*neg;
 15 }
 16
 17 int N,Q;
 18 int eg[maxn*2][2],egh[maxn],ect;
 19 int fa[maxn][22],dep[maxn],dfn[maxn],tot,siz[maxn];
 20
 21 inline void adeg(int a,int b){
 22     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
 23 }
 24
 25 inline void dfs1(int x){
 26     dfn[x]=++tot;
 27     for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++){
 28         fa[x][i+1]=fa[fa[x][i]][i];
 29     }
 30     siz[x]=1;
 31     for(int i=egh[x];i;i=eg[i][1]){
 32         int b=eg[i][0];if(b==fa[x][0]) continue;
 33         fa[b][0]=x,dep[b]=dep[x]+1;
 34         dfs1(b);siz[x]+=siz[b];
 35     }
 36 }
 37
 38 inline int jump(int x,int d){
 39     int i=0;
 40     while(d){
 41         if(d&1) x=fa[x][i];
 42         i++,d>>=1;
 43     }return x;
 44 }
 45
 46 inline int getlca(int x,int y){
 47     if(dep[x]<dep[y]) swap(x,y);
 48     for(int i=log2(dep[x]-dep[y]);i>=0&&dep[x]!=dep[y];i--){
 49         if(dep[fa[x][i]]>=dep[y])
 50             x=fa[x][i];
 51     }
 52     if(x==y) return x;
 53     for(int i=log2(dep[x]);i>=0;i--){
 54         if(fa[x][i]!=fa[y][i])
 55             x=fa[x][i],y=fa[y][i];
 56     }
 57     return fa[x][0];
 58 }
 59
 60 inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
 61
 62 int xfa[maxn],xsh[maxn],xbr[maxn];
 63
 64 int h[maxn],stk[maxn],hd,len[maxn];
 65 int ans[maxn],id[maxn],pct;
 66 bool rea[maxn];
 67 inline void connect(int x,int y){
 68     // printf("\t\tconnect:%d %d\n",x,y);
 69     xfa[x]=y,xbr[x]=xsh[y],xsh[y]=x,len[x]=dep[x]-dep[y];
 70 }
 71 inline void build(int m){
 72     sort(h+1,h+m+1,cmp);
 73     stk[hd=1]=1;id[++pct]=1;
 74     for(int i=1;i<=m;i++){
 75         rea[h[i]]=1;id[++pct]=h[i];
 76         int lca=getlca(stk[hd],h[i]);
 77         int lst=0;
 78         while(dfn[stk[hd]]>dfn[lca]){
 79             if(lst) connect(lst,stk[hd]);
 80             lst=stk[hd--];
 81         }if(stk[hd]!=lca) stk[++hd]=lca,id[++pct]=lca;
 82         if(lst) connect(lst,stk[hd]);
 83         if(h[i]!=1) stk[++hd]=h[i];
 84     }
 85     while(hd>1) connect(stk[hd],stk[hd-1]),hd--;
 86 }
 87 pa up[maxn],dw[maxn];
 88 inline void dfs2(int x){
 89     if(rea[x]) dw[x]=mp(0,x);
 90     else dw[x]=mp(inf,0);
 91     for(int i=xsh[x];i;i=xbr[i]){
 92         dfs2(i);
 93         dw[x]=min(dw[x],mp(dw[i].first+len[i],dw[i].second));
 94     }
 95 }
 96 inline void dfs3(int x){
 97     if(rea[x]) up[x]=mp(0,x);
 98     else if(x==1) up[x]=mp(inf,0);
 99     pa m=mp(inf,0),s=mp(inf,0);
100     for(int i=xsh[x];i;i=xbr[i]){
101         s=min(s,mp(dw[i].first+len[i],dw[i].second));
102         if(s<m) swap(s,m);
103     }
104     for(int i=xsh[x];i;i=xbr[i]){
105         up[i]=mp(up[x].first+len[i],up[x].second);
106         if(dw[i].first+len[i]==m.first&&dw[i].second==m.second){
107             up[i]=min(up[i],mp(s.first+len[i],s.second));
108         }else up[i]=min(up[i],mp(m.first+len[i],m.second));
109         dfs3(i);
110     }
111     if(x!=1){
112         int n=min(dw[x],up[x]).first+len[x]+min(dw[xfa[x]],up[xfa[x]]).first,mi=min(dw[xfa[x]],up[xfa[x]]).second;
113         if(!(n&1)&&mi<min(dw[x],up[x]).second) n--;
114         n>>=1,n-=min(dw[x],up[x]).first;
115         if(n>len[x]) n--;
116         if(n>=0){
117             int y=jump(x,n),z=jump(x,len[x]-1);
118             ans[min(dw[x],up[x]).second]+=siz[y]-siz[x],ans[mi]+=siz[z]-siz[y];
119         }
120
121     }
122     int ss=siz[x];
123     for(int i=xsh[x];i;i=xbr[i]) ss-=siz[jump(i,len[i]-1)];
124     ans[min(dw[x],up[x]).second]+=ss;
125 }
126
127
128 int hh[maxn];
129 int main(){
130     //freopen("","r",stdin);
131     int i,j,k;
132     N=rd();
133     for(i=1;i<N;i++){
134         int a=rd(),b=rd();
135         adeg(a,b);adeg(b,a);
136     }dep[1]=1;dfs1(1);
137     // for(i=1;i<=N;i++) printf("~%d %d\n",i,siz[i]);
138     Q=rd();
139     for(i=1;i<=Q;i++){
140         int m=rd();
141         for(j=1;j<=m;j++) hh[j]=h[j]=rd();
142         build(m);
143         dfs2(1),dfs3(1);
144         for(j=1;j<=m;j++) printf("%d ",ans[hh[j]]);
145         printf("\n");
146         for(;pct;pct--) xfa[id[pct]]=xbr[id[pct]]=xsh[id[pct]]=rea[id[pct]]=ans[id[pct]]=0;
147     }
148     return 0;
149 }
150 /*
151 21
152 1 2
153 2 3
154 2 4
155 3 9
156 4 5
157 5 6
158 6 7
159 6 8
160 2 18 2 19 2 20 2 21
161 9 13 9 14
162 5 17
163 4 15 4 16
164 6 10 10 11 10 12
165 1
166 3
167 9 7 8
168 */

原文地址:https://www.cnblogs.com/Ressed/p/9997771.html

时间: 2024-10-12 19:23:55

luogu3233 世界树 (虚树)的相关文章

【BZOJ-3572】世界树 虚树 + 树形DP

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种

[HNOI2014][BZOJ3572] 世界树|虚树|树上倍增LCA|树型dp|dfs序

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 555  Solved: 319[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.    世界树的形态可以用一个数学模型来描述:世界树中有n个种

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

BZOJ 3572 世界树(虚树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 思路:建立虚树,然后可以发现,每条边不是同归属于一端,那就是切开,一半给上面,一半给下面. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define N 300005 7 int t

【BZOJ3572】【Hnoi2014】世界树 虚树

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46506883"); } 题解: 首先构建虚树,然后在虚树上DP. 过程很简单. 先找出每个虚树节点 i 旁边最近的询问节点 neari (因为有一些lca也被加入了虚树所以虚树节点不全是询问节点,呃怕你们不懂,但其实

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

数据结构(虚树,动态规划):HNOI 2014 世界树

Hnoi2014 世界树 Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. 世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相 同.有的聚居地之间有双向的道路相连,道路的长度为1.保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互

BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. 世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同.有的聚居地之间有双向的道路相连,道路的长度为1.保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环.定义两个聚居地之间的距

虚树初探

虚树其实没什么的.. 只是因为点太多了不能全开于是只开那些需要用到的点. 一棵虚树包括要求点以及它们的lca.. 虚树的构建...(其实感觉如果会虚树的构建的话接下来就是树dp啦没什么的... 首先我们应该对整棵树dfs,求出它的dfs序列.然后对于给的点,按dfs排序.. 因为我们是按dfs序排列的,所以虚树一定是由一条条链构成的.. 扫一遍给的点,如果这个点在当前的这条链上,那加在栈顶就可以了. 如果不是的话,那就不断地退栈使的原来的那条链上面的边全部被加到边集中.. rep(i,1,n){