bzoj 3572: [Hnoi2014]世界树

再次跪虚树(DP)(两遍DP挺有意思的。。)

(这个题的情况,,跪)

%%%http://hzwer.com/6804.html

  1 #include <bits/stdc++.h>
  2 #define LL long long
  3 #define N 300005
  4 using namespace std;
  5 inline int ra()
  6 {
  7     int x=0,f=1; char ch=getchar();
  8     while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
  9     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
 10     return x*f;
 11 }
 12 int bin[20];
 13 int n,m,q,cnt,tot,K,ind;
 14 int fa[N][20],deep[N],head[N],dfn[N],size[N];
 15 int a[N],b[N],f[N];
 16 int top,st[N],c[N];
 17 int rem[N],belong[N];
 18 struct edge{
 19     int to,next;
 20 }e[N<<1];
 21 void pre_bin(){bin[0]=1; for (int i=1; i<20; i++) bin[i]=bin[i-1]<<1;}
 22 void insert(int x, int y){
 23     if (x==y) return;
 24     e[++cnt].next=head[x]; e[cnt].to=y; head[x]=cnt;
 25     }
 26 void dfs(int x)
 27 {
 28     for (int i=1; bin[i]<=deep[x]; i++)
 29         fa[x][i]=fa[fa[x][i-1]][i-1];
 30     size[x]=1; dfn[x]=++ind;
 31     for (int i=head[x];i;i=e[i].next)
 32     {
 33         if (e[i].to==fa[x][0]) continue;
 34         fa[e[i].to][0]=x;
 35         deep[e[i].to]=deep[x]+1;
 36         dfs(e[i].to);
 37         size[x]+=size[e[i].to];
 38     }
 39 }
 40 int lca(int x, int y)
 41 {
 42     if (deep[x]<deep[y]) swap(x,y);
 43     int t=deep[x]-deep[y];
 44     for (int i=0; bin[i]<=t; i++)
 45         if (bin[i]&t) x=fa[x][i];
 46     for (int i=19; i>=0; i--)
 47         if (fa[x][i]!=fa[y][i])
 48             x=fa[x][i],y=fa[y][i];
 49     return x==y?x:fa[x][0];
 50 }
 51 bool cmp(int a, int b){return dfn[a]<dfn[b];}
 52 void build_vtree()
 53 {
 54     sort(a+1,a+K+1,cmp);
 55     cnt=top=tot=0; int flag=0;
 56     if (belong[1]!=1) st[++top]=1;
 57     for (int i=1+flag; i<=K; i++)
 58     {
 59         int x=a[i],f=lca(x,st[top]);
 60         if (f==st[top]) {st[++top]=x; continue;}
 61         while (f==lca(st[top-1],x))
 62         {
 63             insert(st[top-1],st[top]); top--;
 64             f=lca(x,st[top]);
 65         }
 66         insert(f,st[top]); st[top]=f; st[++top]=x;
 67     }
 68     while(top>1)insert(st[top-1],st[top]),top--;
 69 }
 70 int dis(int x, int y)
 71 {
 72     return deep[x]+deep[y]-2*deep[lca(x,y)];
 73 }
 74 void dfs1(int x)
 75 {
 76     c[++tot]=x; rem[x]=size[x];
 77     for (int i=head[x];i;i=e[i].next)
 78     {
 79         dfs1(e[i].to);
 80         if (!belong[e[i].to]) continue;
 81         int t1=dis(belong[e[i].to],x),t2=dis(belong[x],x);
 82         if ((t1==t2 && belong[e[i].to]<belong[x]) || t1<t2 || !belong[x])
 83             belong[x]=belong[e[i].to];
 84     }
 85 }
 86 void dfs2(int x)
 87 {
 88     for (int i=head[x];i;i=e[i].next)
 89     {
 90         int t1=dis(belong[x],e[i].to),t2=dis(belong[e[i].to],e[i].to);
 91         if ((t1==t2 && belong[e[i].to]>belong[x]) || t1<t2|| !belong[e[i].to])
 92             belong[e[i].to]=belong[x];
 93         dfs2(e[i].to);
 94     }
 95 }
 96 void query(int a, int b)
 97 {
 98     int x=b,mid=b;
 99     for (int i=18; i>=0; i--)
100         if (deep[fa[x][i]]>deep[a]) x=fa[x][i];
101     rem[a]-=size[x];
102     if (belong[a]==belong[b])
103     {
104         f[belong[a]]+=size[x]-size[b];
105         return;
106     }
107     for (int i=18; i>=0; i--)
108     {
109         int nxt=fa[mid][i];
110         if (deep[nxt]<=deep[a]) continue;
111         int t1=dis(belong[a],nxt),t2=dis(belong[b],nxt);
112         if (t1>t2 || (t2==t1 && belong[b]<belong[a])) mid=nxt;
113     }
114     f[belong[a]]+=size[x]-size[mid];
115     f[belong[b]]+=size[mid]-size[b];
116 }
117 void solve()
118 {
119     K=ra();
120     for (int i=1; i<=K; i++) a[i]=b[i]=ra();
121     for (int i=1; i<=K; i++) belong[a[i]]=a[i];
122     build_vtree();
123     dfs1(1); dfs2(1);
124     for (int i=1; i<=tot; i++)
125         for (int j=head[c[i]];j;j=e[j].next)
126             query(c[i],e[j].to);
127     for (int i=1; i<=tot; i++)
128         f[belong[c[i]]]+=rem[c[i]];
129     for (int i=1; i<=K; i++) printf("%d ",f[b[i]]);
130     for (int i=1; i<=tot; i++)
131             f[c[i]]=belong[c[i]]=head[c[i]]=rem[c[i]]=0;
132     puts("");//while (1);
133 }
134 int main(int argc, char const *argv[])
135 {
136     n=ra(); pre_bin();
137     for (int i=1; i<n; i++)
138     {
139         int x=ra(),y=ra();
140         insert(x,y); insert(y,x);
141     }
142     dfs(1);
143     memset(head,0,sizeof(head));
144     m=ra();
145     for (int i=1; i<=m; i++)  solve();
146     return 0;
147 }
时间: 2024-10-09 18:00:43

bzoj 3572: [Hnoi2014]世界树的相关文章

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

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

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

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

BZOJ 3572 【HNOI2014】 世界树

题目链接:世界树 首先看到\(\sum m_i\le 3\times 10^5\)这个条件,显然这道题就需要用虚树了. 在我们构建出虚树之后,就可以用两遍\(dfs\)来求出离每个点最近的议事处了.然后,如果一个点和它在虚树上的父亲所属的议事处不同,那么在原树中的两点之间的路径上就会存在一个分界点,倍增出这个分界点算答案即可.注意不能用路径长度来算,需要使用子树大小. 然后我们还需要考虑那些不在虚树中的点.我们可以令\(f_x\)表示原树上\(x\)子树中和\(x\)属于同一个议事处的点的个数,

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

bzoj千题计划255:bzoj3572: [Hnoi2014]世界树

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 明显需要构造虚树 点属于谁管理分三种情况: 1.属于虚树的点 2.在虚树上的边上的点 3.既不属于虚树的点,又不属于虚树上的边的点 第一种情况: 先做一遍树形dp,得到子树中距离它最近的点 再dfs一遍,看看父节点那一块 是否有比它现在的点更近的点 第二种情况: 一条边u-->v 如果u和v属于同一点x管理,那么这条边所代表的所有点也都属于x管理 否则的话,二分一个点tmp,tmp以上的点归

bzoj3572[Hnoi2014]世界树

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 首先我们先构建出虚树 然后在虚树上DP,求出虚树上每个点离最近的临时议事处在哪里 对于虚树上相邻的两个点$u$和$v$,他们连线上一定存在一个分界处,一边一定会去离$u$最近的临时议事处:另一边一定会去离$v$最近的临时议事处 然后就做完了 #include<cstdio> #include<cstdlib> #include<iostream> #include&

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

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

[BZOJ 3573][Hnoi2014]米特运输(乱搞)

Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都.这N个城市由N-1条单向高速 通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲.树按深度分层: 根结点深度为0,属于第1层:根结点的子节点深度为1,属于第2层:依此类推,深度为i的结点属于第i+l层.建好 高速通道之后,D星人开始考虑如何具体地储存和传输米

bzoj 3575: [Hnoi2014]道路堵塞

Description A 国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所有从城市1到城市N的路径中最短的.不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞. 现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少. Input 输入文件第一行是三个用空格分开的正整数N.M和L,分别表示城市数目.单向道路数目