BZOJ 3572 [HNOI2014]世界树 (虚树+DP)
题目大意:略
细节贼多的虚树$DP$
先考虑只有一次询问的情况
一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖
跑两次$dfs$即可,时间$O(n)$
再考虑一条链的情况
一条链上有很多个特殊点,相邻两个特殊点$x,y$之间可能有很多连续的非特殊点,那么在这些连续的非特殊点上会有一个分界,前面一部分被$x$管辖,后面一部分被$y$管辖
在链上二分即可,时间$O(mlogm)$
正解就是把上面两种情况结合起来..用虚树维护一下
首先根据套路对特殊点建出虚树,虚树上会出现所有的特殊点以及一些作为$LCA$的非特殊点。
用第一种情况的方法在虚树上搜索一遍,求出虚树上的每个节点被哪些节点管辖
再考虑剩余节点的贡献
对于虚树上相邻的两个节点$x,y$,假设$dep[x]<dep[y]$,我们取出原树上端点为$x,y$的链$F$,然后把$F$的两个端点$x,y$去掉,贡献分为两种情况
$x,y$被同一个的节点管辖,那么链F上的节点以及链F上挂着的子树也都会被这个节点管辖
$x,y$被不同的节点管辖,借用第二种情况的方法,链F上一定存在一个分界点,上面一部分被管辖x的节点管辖,下面一部分被管辖y的节点管辖,倍增跳一下即可
看起来很好写,实际上细节真的不少啊..上午迷迷糊糊写+调了4h才过
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define N1 300100
using namespace std;
const int inf=0x3f3f3f3f; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
}
template <typename _T> _T chkmin(_T &x,_T &y,_T vx,_T vy)
{
if(vx<vy) return x;
if(vx>vy) return y;
return x<y?x:y;
} struct Edge{
int to[N1*],nxt[N1*],head[N1],cte;
void ae(int u,int v)
{ cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; } //val[cte]=w;
void clr()
{ memset(to,,(cte+)*); memset(nxt,,(cte+)*); cte=; }
}e,g; int n,de;
int lg[N1*];
int dep[N1],ff[N1][],eu[N1*][],st[N1],sz[N1],cur; void dfs(int x)
{
int j,v; ff[x][]=x; eu[st[x]=++cur][]=x;
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j]; if(v==ff[x][]) continue;
ff[v][]=x; dep[v]=dep[x]+;
dfs(v);
eu[++cur][]=x; sz[x]+=sz[v];
}
sz[x]++;
}
void get_st()
{
int i,j;
for(j=;j<=;j++)
for(i=;i<=n;i++)
ff[i][j]=ff[ ff[i][j-] ][j-];
for(i=,lg[]=;i<=cur;i++) lg[i]=lg[i>>]+;
for(j=;j<=lg[cur];j++)
for(i=;i+(<<j)-<=cur;i++)
eu[i][j]=dep[eu[i][j-]] < dep[eu[i+(<<(j-))][j-]] ? eu[i][j-] : eu[i+(<<(j-))][j-];
}
int LCA(int x,int y)
{
x=st[x], y=st[y]; if(x>y) swap(x,y); int l=y-x+;
return dep[eu[x][lg[l]]] < dep[eu[y-(<<lg[l])+][lg[l]]] ? eu[x][lg[l]] : eu[y-(<<lg[l])+][lg[l]];
}
int Dis(int x,int y)
{
if(!x||!y) return inf; int F=LCA(x,y);
return dep[x]+dep[y]-*dep[F];
}
int jump(int x,int D)
{
int i;
for(i=lg[dep[x]-D]+;i>=;i--)
if(ff[x][i] && dep[ff[x][i]]>=D) x=ff[x][i];
return x;
} namespace virtree{ int cmp_dfsorder(int x,int y){ return st[x]<st[y]; }
int vir[N1],num,stk[N1],tp,ctrl[N1],spe[N1],ans[N1],org[N1],dctrl[N1]; void push(int x)
{
int y=stk[tp], F=LCA(x,y); stk[]=F;
while(tp> && dep[stk[tp-]]>dep[F])
{
g.ae(stk[tp-],stk[tp]);
stk[tp]=; tp--;
}
if(dep[stk[tp]]>dep[F])
{
g.ae(F,stk[tp]);
stk[tp]=; tp--;
}
if(!tp||stk[tp]!=F) stk[++tp]=F;
if(stk[tp]!=x) stk[++tp]=x;
}
int build()
{
int i;
for(i=;i<=num;i++) spe[vir[i]]=, org[i]=vir[i];
if(!spe[]) vir[++num]=;
sort(vir+,vir+num+,cmp_dfsorder);
stk[++tp]=vir[];
for(i=;i<=num;i++) push(vir[i]);
while(tp>) g.ae(stk[tp-],stk[tp]), tp--;
return stk[tp];
} int dfs_son(int x)
{
int j,v,mi=;
for(j=g.head[x];j;j=g.nxt[j])
{
v=g.to[j]; dfs_son(v);
mi=chkmin(ctrl[v],mi,dep[ctrl[v]],dep[mi]);
}
ctrl[x]=(spe[x]?x:mi);
return ctrl[x];
}
void dfs_fa(int x)
{
int j,v;
for(j=g.head[x];j;j=g.nxt[j])
{
v=g.to[j];
ctrl[v]=chkmin(ctrl[x],ctrl[v],Dis(ctrl[x],v),Dis(ctrl[v],v));
dfs_fa(v);
}
}
void debug(int x)
{
int j,v;
if(spe[x]) printf("%d ",x);
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j]; if(v==ff[x][]) continue;
debug(v);
}
}
void dfs_ans(int x)
{
int j,v,sum=sz[x],cx=ctrl[x]; dctrl[x]=Dis(x,ctrl[x]);
for(j=g.head[x];j;j=g.nxt[j])
{
v=g.to[j]; dfs_ans(v);
int cv=ctrl[v],p,pv,tmp;
pv=jump(v,dep[x]+);
sum-=sz[pv];
if(dep[v]==dep[x]+) continue;
if(cx!=cv){
tmp=dctrl[x]+dctrl[v]+dep[v]-dep[x];
if(tmp&){
p=dep[v]-((tmp-)/-dctrl[v]);
p=jump(v, min(dep[v],max(dep[x]+,p)) );
}else{
p=dep[v]-((tmp-)/-dctrl[v]);
if(p<=dep[v]){
p=jump(v, min(dep[v],max(dep[x]+,p)) );
if(cv<cx && dep[p]->=dep[x]+) p=ff[p][];
}else p=v;
}
ans[cx]+=sz[pv]-sz[p], ans[cv]+=sz[p]-sz[v];
}else{
ans[cx]+=sz[pv]-sz[v];
}
}
ans[cx]+=sum;
}
void dfs_clear(int x)
{
int j,v;
for(j=g.head[x];j;j=g.nxt[j])
{
v=g.to[j]; dfs_clear(v);
}
g.head[x]=ctrl[x]=spe[x]=ans[x]=;
} void solve(int Num)
{
num=Num;
int root=build(),i;
dfs_son(root);
dfs_fa(root);
dfs_ans(root);
for(i=;i<=Num;i++) if(i!=Num) printf("%d ",ans[org[i]]); else printf("%d\n",ans[org[i]]);
dfs_clear(root);
memset(vir,,(num+)*); memset(org,,(num+)*); memset(stk,,(tp+)*); g.clr(); tp=;
} }; int main()
{
int i,j,ans=,x,y,q,Q;
scanf("%d",&n);
for(i=;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
dfs(); get_st(); dep[]=inf;
scanf("%d",&Q);
for(q=;q<=Q;q++)
{
read(x);
for(i=;i<=x;i++) read(virtree::vir[i]);
virtree::solve(x);
}
return ;
}
BZOJ 3572 [HNOI2014]世界树 (虚树+DP)的更多相关文章
- BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]
传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$ ...
- bzoj 3572: [Hnoi2014]世界树 虚树 && AC500
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 520 Solved: 300[Submit][Status] ...
- BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp
https://www.lydsy.com/JudgeOnline/problem.php?id=3572 http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写 ...
- bzoj 3572 [Hnoi2014]世界树——虚树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...
- bzoj 3572: [Hnoi2014]世界树 虚树
题目: Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生 ...
- 【BZOJ】3572: [Hnoi2014]世界树 虚树+倍增
[题意]给定n个点的树,m次询问,每次给定ki个特殊点,一个点会被最近的特殊点控制,询问每个特殊点控制多少点.n,m,Σki<=300000. [算法]虚树+倍增 [题解]★参考:thy_asd ...
- bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增
[Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1921 Solved: 1019[Submit][Status][Dis ...
- 洛谷 P3233 [HNOI2014]世界树(虚树+dp)
题面 luogu 题解 数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\) 以下摘自hzwer博客: 构建虚树以后两遍dp处理出虚树上每个点最近的议事处 然后枚举虚树上每一条边,考虑其对两端 ...
- BZOJ 3572: [Hnoi2014]世界树
BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...
随机推荐
- Ubuntu13.10添加/删除PPA
什么是ppa ppa即Personal Package Archive(个人安装包文档),简单来说就是一些个人或者团体通过独立的网站发布的第三方的软件源.将这些软件源添加到你的电脑上后,你就可以像使用 ...
- ping测试局域网内主机是否alive
[root@zabbix ~]# cat alivehost.sh #!/bin/bash #Checks to see if hosts 192.168.1.100-192.168.1.200 ar ...
- ios11--UIButton
// // ViewController.m // 02-UIButton(在代码中使用) // #import "ViewController.h" @interface Vie ...
- hibernate中id中的 precision 和 scale 作用
转自:https://www.cnblogs.com/IT-Monkey/p/4077570.html <hibernate-mapping> <class name=&qu ...
- Knights of the Round Table(Tarjan+奇圈)
http://poj.org/problem?id=2942 题意:n个武士,某些武士之间相互仇视,如果在一起容易发生争斗事件.所以他们只有满足一定的条件才能参加圆桌会议:(1)相互仇视的两个武士不能 ...
- canvas做的一个写字板
<!DOCTYPE html><html><head><title>画板实验</title> <meta charset=" ...
- 关于 node.js 小插曲
随着web2.0的时代到来,javascript在前端担任了更多的职责,事件也看得到了广泛的应用,node不像rhino那样受java的影响很大,而是将前端浏览器中应用广泛企鹅成熟的事件引入后端,配合 ...
- 《Typecript 入门教程》 2、访问控制符:public、private、protected、readonly
声明类的属性和方法时可以设置使用访问控制符,访问控制符设置类的属性和方法能不能在类的外部被访问 1. 默认为 public,使用public定义的属性和方法在类的内部和外部都可以访问 2. priva ...
- 【洛谷2469/BZOJ1927】[SDOI2010]星际竞速(费用流/最小路径覆盖)
题目: 洛谷2469 分析: 把题目翻译成人话:给一个带边权的DAG,求一个路径覆盖方案使路径边权总和最小.从点\(i\)开始的路径需要额外加上\(A_i\)的权值. 回xian忆chang一xue下 ...
- ACM_绝对值排序
Why Males And Females Apart? Time Limit: 2000/1000ms (Java/Others) Problem Description: In so many o ...