【BZOJ3572】[Hnoi2014]世界树 虚树

时间:2022-10-13 23:28:37

【BZOJ3572】[Hnoi2014]世界树

Description

世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所卧a与c之间的距离为2。
出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

Input

第一行为一个正整数n,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
向道路。接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

Output

输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

Sample Input

10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8

Sample Output

1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1

HINT

N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000

题解:先建立虚树,然后处理出对于虚树上的每个节点,离它最近的议事处的编号xi及距离di,然后考虑不再虚树上的点:

如果某个连通块中的点只有一种途径到达虚树上的点,那么他们显然只能归那个点的xi管辖,直接统计一下就好。

如果某个连通块中的点有两种途径到达虚树上的点,那么他们要被这两个点分掉。我们根据di算出分割点,然后倍增找到这个点,那么在上侧的点会被上面的点管辖,下侧的点被下侧的管辖,统计一下siz就好。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=300010;
int n,m,tot,top,rt,cnt;
int to[maxn<<1],next[maxn<<1],head[maxn],dep[maxn],fa[20][maxn],p[maxn],q[maxn],Log[maxn],siz[maxn],vis[maxn];
int st[maxn],f[maxn],pos[maxn];
vector<int> ch[maxn];
struct node
{
int v,x;
node() {}
node(int a,int b) {v=a,x=b;}
node operator + (const int &a) const {return node(v+a,x);}
bool operator < (const node &a) const {return (v==a.v)?(x<a.x):v<a.v;}
}s[maxn];
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
bool cmp(int a,int b)
{
return (pos[a]>pos[b]);
}
void dfs(int x)
{
pos[x]=++pos[0],siz[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x])
fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]),siz[x]+=siz[to[i]];
}
inline int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a];
if(a==b) return a;
for(int i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b];
return fa[0][a];
}
inline int FA(int x,int y)
{
for(int i=Log[y];i>=0;i--) if((1<<i)<=y) y-=(1<<i),x=fa[i][x];
return x;
}
void dfs1(int x)
{
int i,y;
if(vis[x]) s[x]=node(0,x);
else s[x]=node(1<<20,0);
for(i=0;i<(int)ch[x].size();i++) y=ch[x][i],dfs1(y),s[x]=min(s[x],s[y]+(dep[y]-dep[x]));
}
void dfs2(int x)
{
int i,y,z,k;
f[s[x].x]+=siz[x];
for(i=0;i<(int)ch[x].size();i++)
{
y=ch[x][i],s[y]=min(s[y],s[x]+(dep[y]-dep[x])),dfs2(y);
z=FA(y,dep[y]-dep[x]-1),f[s[x].x]-=siz[z];
if(s[x].x==s[y].x) f[s[x].x]+=siz[z]-siz[y];
else
{
if(s[x].x<s[y].x) k=FA(y,(s[x].v-s[y].v+dep[y]-dep[x]-1)/2);
else k=FA(y,(s[x].v-s[y].v+dep[y]-dep[x])/2);
f[s[x].x]+=siz[z]-siz[k],f[s[y].x]+=siz[k]-siz[y];
}
}
ch[x].clear();
}
int main()
{
n=rd();
int i,j,a,b;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dep[1]=1,dfs(1);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];
m=rd();
for(i=1;i<=m;i++)
{
tot=rd();
for(j=1;j<=tot;j++) q[j]=p[j]=rd(),vis[p[j]]=1;
sort(p+1,p+tot+1,cmp);
st[top=1]=p[1];
for(j=2;j<=tot;j++)
{
a=lca(p[j-1],p[j]);
while(top&&dep[st[top]]>dep[a])
{
b=st[top],top--;
if(top&&dep[st[top]]>dep[a]) ch[st[top]].push_back(b);
else ch[a].push_back(b);
}
if(!top||st[top]!=a) st[++top]=a;
if(st[top]!=p[j]) st[++top]=p[j];
}
while(top>1) ch[st[top-1]].push_back(st[top]),top--;
rt=st[top];
dfs1(rt);
dfs2(rt);
f[s[rt].x]+=n-siz[rt];
for(j=1;j<=tot;j++) printf("%d ",f[q[j]]),f[q[j]]=vis[q[j]]=0;
puts("");
}
return 0;
}//10 2 1 3 2 4 3 5 4 6 1 7 3 8 3 9 4 10 1 5 2 6 1 5 2 7 3 6 9 1 8 4 8 7 10 3 5 2 9 3 5 8

【BZOJ3572】[Hnoi2014]世界树 虚树的更多相关文章

  1. bzoj3572&lbrack;Hnoi2014&rsqb; 世界树 虚树&plus;dp&plus;倍增

    [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1921  Solved: 1019[Submit][Status][Dis ...

  2. 【BZOJ-3572】世界树 虚树 &plus; 树形DP

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status ...

  3. bzoj 3572&colon; &lbrack;Hnoi2014&rsqb;世界树 虚树 &amp&semi;&amp&semi; AC500

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 520  Solved: 300[Submit][Status] ...

  4. bzoj 3572&colon; &lbrack;Hnoi2014&rsqb;世界树 虚树

    题目: Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生 ...

  5. BZOJ 3572&colon; &lbrack;Hnoi2014&rsqb;世界树 &lbrack;虚树 DP 倍增&rsqb;

    传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$ ...

  6. bzoj 3572 &lbrack;Hnoi2014&rsqb;世界树——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...

  7. BZOJ 3572&colon; &lbrack;Hnoi2014&rsqb;世界树 虚树 树形dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=3572 http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写 ...

  8. 【BZOJ】3572&colon; &lbrack;Hnoi2014&rsqb;世界树 虚树&plus;倍增

    [题意]给定n个点的树,m次询问,每次给定ki个特殊点,一个点会被最近的特殊点控制,询问每个特殊点控制多少点.n,m,Σki<=300000. [算法]虚树+倍增 [题解]★参考:thy_asd ...

  9. 洛谷 P3233 &lbrack;HNOI2014&rsqb;世界树&lpar;虚树&plus;dp&rpar;

    题面 luogu 题解 数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\) 以下摘自hzwer博客: 构建虚树以后两遍dp处理出虚树上每个点最近的议事处 然后枚举虚树上每一条边,考虑其对两端 ...

随机推荐

  1. Spatial pyramid pooling &lpar;SPP&rpar;-net (空间金字塔池化)笔记(转)

    在学习r-cnn系列时,一直看到SPP-net的身影,许多有疑问的地方在这篇论文里找到了答案. 论文:Spatial Pyramid Pooling in Deep Convolutional Net ...

  2. 关于Java中的选择排序法和冒泡排序法

    一,这种方法是直接传入一个数组进行排序(选择排序法) public static void selectSort(int arr[]){ for (int i = 0; i < arr.leng ...

  3. &lbrack;笔记&rsqb; C&num; Windows Phone 8 WP8 开发,判断目前网路是否可用。

    原文:[笔记] C# Windows Phone 8 WP8 开发,判断目前网路是否可用. 常常我们在开发Windows Phone 8 App时会使用网路来读取网页的资料或其他开放平台的Json.X ...

  4. 保护模式特权级别DPL&comma;RPL&comma;CPL 之间的联系和区别

    RPL是段选择子里面的bit 0和bit 1位组合所得的值,但这里要首先搞清楚什么是段选择子,根据Intel 的文件(IA-32 IntelR Architecture Software Develo ...

  5. K-means聚类 的 Python 实现

    K-means聚类 的 Python 实现 K-means聚类是一个聚类算法用来将 n 个点分成 k 个集群. 算法有3步: 1.初始化– K 个初始质心会被随机生成 2.分配 – K 集群通过关联到 ...

  6. Hexo &plus; GitEE 搭建、备份、恢复、多终端

    Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页. Hexo 是使用的比较多的博客框架了,我也尝试自己搭 ...

  7. Kali Linux Vmware虚拟机(新手)安装

    准备工作: 1.安装VMware workstation 软件 2.下载好kali linux 的ios系统文件 3.打开电脑的虚拟化支持(Intel VT-x/EPT或AMD-V/RVI(V)) 虚 ...

  8. const和define的差别

    1.const有什么用途?(1)可以定义const常量(2)const可以修饰函数的参数和返回值,甚至函数的定义体.被const修饰的东西都受到强制保护,可以预防以外的变动,能提高程序的健壮性. in ...

  9. scala-02-数组的操作

    scala中的数组和 java中的数组一样, 定义了长度后不可改变 1, 产生一个数组: 有3种创建数组的方式, 分别直接new, 直接赋值, 或者使用 Array中的rang来产生 /** * 获取 ...

  10. canvas移动端常用技巧图片loading

    核心知识点:drawImage 作用:将图片加载在canvas html: <canvas id="myCanvas" width="200" heigh ...