BZOJ 3572: [Hnoi2014]世界树

来源:互联网 发布:查看nginx运行状态 编辑:程序博客网 时间:2024/05/16 01:38

好久没有做虚树了,感觉好虚啊

首先建出虚树,然后对于两边dp搞出虚树上每个点连接到的居委会

对于虚树上的每条边,我们找到两端点的分界点,再对他们连接到的居委会更新答案

这里给树剖加个特技就能求两点间第K个点了

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=300000+5;const int inf=1e9;int read(){char ch=getchar();int x=0,f=1;while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}struct Edge{int to,next;}e[N<<1];int head[N],cnt;void ins(int u,int v){if(u==v)return;e[++cnt]=(Edge){v,head[u]};head[u]=cnt;}void insert(int u,int v){ins(u,v);ins(v,u);}bool is[N];int dep[N],fa[N],siz[N],son[N],top[N],pos[N],node[N],sz,dfn[N],dfs_clock;void dfs(int u){siz[u]=1;son[u]=0;dfn[u]=++dfs_clock;for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(v==fa[u])continue;fa[v]=u;dep[v]=dep[u]+1;dfs(v);siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;}}void dfs(int u,int tp){top[u]=tp;pos[u]=++sz;node[sz]=u;if(son[u])dfs(son[u],tp);for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(v!=fa[u]&&v!=son[u])dfs(v,v);}}bool cmp(int u,int v){if(dep[u]==dep[v])return u<v;return dep[u]<dep[v];}int lca(int u,int v){while(top[u]!=top[v])if(dep[top[u]]>dep[top[v]])u=fa[top[u]];else v=fa[top[v]];return min(u,v,cmp);}int dis(int u,int v){if(!u||!v)return inf;return dep[u]+dep[v]-2*dep[lca(u,v)];}int lin[N],f[N];void dp1(int u){f[u]=0;if(is[u])lin[u]=u;for(int i=head[u];i;i=e[i].next){int v=e[i].to;dp1(v);lin[u]=min(lin[u],lin[v],cmp);}}void dp2(int u){for(int i=head[u];i;i=e[i].next){int v=e[i].to;int t1=dis(lin[e[i].to],e[i].to),t2=dis(lin[u],e[i].to);if(t1==t2)lin[e[i].to]=min(lin[e[i].to],lin[u]);else if(t2<t1)lin[e[i].to]=lin[u];dp2(v);}}int size_chain(int u){return dep[u]-dep[top[u]]+1;}int iabs(int x){return x<0?-x:x;}int size_chain(int u,int v){return iabs(dep[u]-dep[v])+1;}int size(int u,int v){return dis(u,v)+1;}int find(int u,int k){if(k<=size_chain(u))return node[pos[u]-k+1];else return find(fa[top[u]],k-size_chain(u));}int find(int u,int v,int k){int w=lca(u,v);if(k<=size_chain(u,w))return find(u,k);else return find(v,size(u,v)-k+1);}int st[N],h[N],b[N];bool cmp1(int u,int v){return dfn[u]<dfn[v];}int work(int u,int v){int x=lin[u],y=lin[v],mid=find(y,x,size(x,y)>>1),t=find(u,v,2);if((size(x,y)&1)&&y<x)mid=fa[mid];if(size(x,mid)<=size(x,u))mid=t;else if(size(y,mid)<=size(y,v))mid=v;f[x]+=siz[t]-siz[mid];f[y]+=siz[mid]-siz[v];}void calc_edge(int u){f[lin[u]]+=siz[u];for(int i=head[u];i;i=e[i].next){int v=e[i].to;f[lin[u]]-=siz[find(u,v,2)];work(u,v);calc_edge(v);}head[u]=0;lin[u]=0;}void solve(){int k=read();for(int i=1;i<=k;i++){h[i]=read();is[h[i]]=true;b[i]=h[i];}sort(h+1,h+1+k,cmp1);int tp;cnt=0;st[tp=1]=1;for(int i=1;i<=k;i++){int now=h[i],f=lca(now,st[tp]);if(f==st[tp]){st[++tp]=now;continue;}while(tp>1&&f==lca(now,st[tp-1])){ins(st[tp-1],st[tp]);tp--;f=lca(now,st[tp]);}ins(f,st[tp]);st[tp]=f;st[++tp]=now;}while(--tp)ins(st[tp],st[tp+1]);dp1(1);dp2(1);calc_edge(1);for(int i=1;i<=k;i++){printf("%d ",f[b[i]]);is[b[i]]=false;}putchar('\n');}int main(){//freopen("a.in","r",stdin);int n=read();for(int i=1;i<n;i++){int u,v;u=read();v=read();insert(u,v);}dfs(1);dfs(1,1);dep[0]=inf;memset(head,0,sizeof(head));int q=read();while(q--)solve();return 0;}
突然发现是RANK6哎,果然树剖就是快

0 0
原创粉丝点击