3572: [Hnoi2014]世界树

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 645  Solved: 362
[Submit][Status][Discuss]

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

Source

【思路】

虚树+Dfs序+DP

   直接在原树上进行DP的方法时间为O(nm),但注意到sigma(m)并不大。所以有了虚树这个东西 =-=

构造一棵虚树,所谓虚树即包含了给定点,并收缩了不分叉边的连通子图(顺的kuangbin的定义)。

基于构树的dfs序,两遍for可以求出每个点被谁管辖,然后再虚树上进行节点的分配。

详见代码。

【代码】

 #include<map>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define mp(x,y) make_pair(x,y)
using namespace std; const int N = +;
const int INF = 1e9+1e9;
const int maxd = ; vector<int> G[N];
int d[N],sz[N],dfn[N],f[N][maxd];
int n,q,dfsc; int cmp(const int &lhs,const int &rhs) { return dfn[lhs]<dfn[rhs];
}
void dfs(int u,int fa) {
dfn[u]=++dfsc;
sz[u]=;
for(int v,i=;i<G[u].size();i++) if((v=G[u][i])!=fa) {
f[v][]=u;
for(int j=;j<maxd;j++) f[v][j]=f[f[v][j-]][j-];
d[v]=d[u]+;
dfs(v,u);
sz[u]+=sz[v];
}
}
int LCA(int u,int v) {
if(d[v]>d[u]) swap(u,v);
for(int i=maxd-;i>=;i--)
if(d[f[u][i]]>=d[v]) u=f[u][i];
if(u==v) return u;
for(int i=maxd-;i>=;i--)
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][];
}
int find(int u,int dep) {
for(int i=maxd-;i>=;i--)
if(d[f[u][i]]>=dep) u=f[u][i];
return u;
} void solve() {
int m,tot=,top=;
//static 可以声明函数内大数组
static int h[N],t[N],mem[N],st[N],val[N],father[N],w[N],ans[N];
static pair<int,int> g[N];
scanf("%d",&m);
for(int i=;i<=m;i++) {
scanf("%d",&h[i]);
mem[i]=h[i];
t[++tot]=h[i];
g[h[i]]=mp(,h[i]);
ans[h[i]]=;
}
sort(h+,h+m+,cmp);
for(int i=;i<=m;i++) {
if(!top) father[st[++top]=h[i]]=;
else {
int p=h[i],lca=LCA(p,st[top]);
for(; d[lca]<d[st[top]];--top)
if(d[st[top-]]<=d[lca])
father[st[top]]=lca;
if(st[top]!=lca) {
father[lca]=st[top];
t[++tot]=lca;
g[lca]=mp(INF,);
st[++top]=lca;
}
st[++top]=p;
father[p]=lca;
}
}
sort(t+,t+tot+,cmp);
for(int i=;i<=tot;i++) {
int p=t[i];
val[p]=sz[p];
if(i>) w[p]=d[p]-d[father[p]]; //路径长
}
//基于dfs序进行两次for 上下不同递推方向比较得最近点
for(int i=tot;i>;i--) {
int p=t[i] , fa=father[p];
g[fa]=min(mp(g[p].first+w[p],g[p].second),g[fa]); //g存储到p最近询问点的长度与编号
}
for(int i=;i<=tot;i++) {
int p=t[i] , fa=father[p];
g[p]=min(mp(g[fa].first+w[p],g[fa].second),g[p]);
}
for(int i=;i<=tot;i++) {
int p=t[i],fa=father[p];
if(i==) ans[g[p].second]+=n-sz[p]; //管辖虚树根节点的 += 原树中虚根上方的节点数
else {
int x=find(p,d[fa]+),sum=sz[x]-sz[p];
val[fa]-=sz[x];
if(g[fa].second==g[p].second) ans[g[p].second]+=sum; // fa与p同是lca式而非询问点
else {
int mid=d[p]-((g[fa].first+g[p].first+w[p])/-g[p].first); //中点距
if((g[fa].first+g[p].first+w[p])%== && g[p].second>g[fa].second) ++mid; //根据序号判断偏向于fa还是p
int y=sz[find(p,mid)]-sz[p];
ans[g[p].second] += y; //fa与p分配管辖点
ans[g[fa].second] += sum-y;
}
}
}
for(int i=;i<=tot;i++)
ans[g[t[i]].second] += val[t[i]]; //剩余未分配点
for(int i=;i<=m;i++) printf("%d ",ans[mem[i]]); puts("");
} int main() {
scanf("%d",&n);
int u,v;
for(int i=;i<n-;i++) {
scanf("%d%d",&u,&v);
G[u].push_back(v) , G[v].push_back(u);
}
d[]=; dfs(,-);
scanf("%d",&q);
while(q--) solve();
return ;
}

bzoj 3572 [Hnoi2014]世界树(虚树+DP)的更多相关文章

  1. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

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

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

  3. bzoj 3572: [Hnoi2014]世界树 虚树 && AC500

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

  4. BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp

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

  5. bzoj 3572 [Hnoi2014]世界树——虚树

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

  6. bzoj 3572: [Hnoi2014]世界树 虚树

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

  7. 【BZOJ】3572: [Hnoi2014]世界树 虚树+倍增

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

  8. bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增

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

  9. 洛谷 P3233 [HNOI2014]世界树(虚树+dp)

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

  10. BZOJ 3572: [Hnoi2014]世界树

    BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...

随机推荐

  1. 第二天——hibernate讲完了

    hibernate 逐步优化 第一步 只按照步骤来提取的 jre包导入错误 第二步 继续封装,把增删改查提取出来,同时进行代码的封装 HQL语句 be stranger in the code .be ...

  2. JAVA DATE解析(时间戳解析为固定格式)

    public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (d ...

  3. Bootstrap Table的例子(转载)

    转载自:http://wenzhixin.net.cn/p/bootstrap-table/docs/examples.html#classes-table 使用的API: data1.json da ...

  4. NRPE: Unable to read output 问题处理总结

    自定义nagios监控命令check_disk_data,首先在nagios服务端command.cfg定义了#'check_disk_data' command definitiondefine c ...

  5. 用java写bp神经网络(四)

    接上篇. 在(一)和(二)中,程序的体系是Net,Propagation,Trainer,Learner,DataProvider.这篇重构这个体系. Net 首先是Net,在上篇重新定义了激活函数和 ...

  6. iOS英文 汉化,如调用相册,相机改“cancel”,“photos”为“取消”,“相机”

    调用系统相册.相机发现是英文的系统相簿界面后标题显示“photos”,但是手机语言已经设置显示中文,纠结半天,最终在info.plist设置解决问题. 只需要改三个地方: 1.plist文件中: 2. ...

  7. 《作业控制系列》-“linux命令五分钟系列”之十

    本原创文章属于<Linux大棚>博客. 博客地址为http://roclinux.cn. 文章作者为roc 希望您能通过捐款的方式支持Linux大棚博客的运行和发展.请见“关于捐款” == ...

  8. Linux mail 命令使用

    linux mail 命令参数: 使用mail发邮件时,必须先将sendmail服务启动. mail –s “邮件主题” –c”抄送地址” –b “密送地址” -- -f 发送人邮件地址 –F 发件人 ...

  9. js string操作总结

    var str = "0123456789"; console.log(str.substring(0)); //------------"0123456789" ...

  10. [ZHUAN]Flask学习记录之Flask-SQLAlchemy

    From: http://www.cnblogs.com/agmcs/p/4445583.html 各种查询方式:http://www.360doc.com/content/12/0608/11/93 ...