题面:BZOJ传送门 洛谷传送门

题目大意:略

细节贼多的虚树$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)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. BZOJ 3572: [Hnoi2014]世界树

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

随机推荐

  1. LeetCode 359. Logger Rate Limiter (记录速率限制器)$

    Design a logger system that receive stream of messages along with its timestamps, each message shoul ...

  2. SoapUI项目书写自我规范

    -->Assertions 判断某个节点存在(_input_name, _button_name) -->Resource 文件夹命名 值去掉红色部分信息 https://mercury- ...

  3. 超级有用的git reset --hard和git revert命令

    很多时候,git新手容易误操作,比如,在levelIISZ-1.4.dev分支下,运行了git pull idc cpp-1.0的结果,这样做麻烦很大,经常导致maven项目格式不正确,这个时候,可以 ...

  4. 使用免费SSL证书让网站支持HTTPS访问

    参考掘金的文章,掘金的文章最详细. https://juejin.im/post/5a31cbf76fb9a0450b6664ee 先检查是否存在 EPEL 源: # 进入目录检查是否存在 EPEL ...

  5. maven的pom.xml文件错误

    来自:http://www.cnblogs.com/shihujiang/p/3492864.html

  6. 9.22 NOIP模拟题

    吉林省信息学奥赛 2017 冬令营                                                                                    ...

  7. P1462 通往奥格瑞玛的道路(二分答案+最短路)

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  8. 使用Keras做OCR时报错:ValueError: Tensor Tensor is not an element of this graph

    现象 项目使用 Flask + Keras + Tensorflow 同样的代码在机器A和B上都能正常运行,但在机器C上就会报如下异常.机器A和B的环境是先安装的,运行.调试成功后才尝试在C上跑. F ...

  9. [Swift通天遁地]七、数据与安全-(4)CoreData数据的增、删、改、查

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  10. .net C# 格式化时间

    1.HtmlEncode="False" 2.DataFormatString="{0:d}" C#格式化日期时间 DateTime dt = DateTime ...