zoukankan      html  css  js  c++  java
  • #虚树,树形dp#洛谷 3233 [HNOI2014]世界树

    题目


    分析

    考虑建一棵虚树,倍增找到虚树上相邻两个点的中间点统计答案
    记录每个虚树点最近的距离以及编号最小的点,主要是细节问题


    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm> 
    #define rr register
    using namespace std;
    const int N=300011; struct node{int y,next;}e[N<<1],E[N];
    int dep[N],siz[N],v[N],dfn[N],tot,f[N][19],a[N],lg[N],stac[N];
    int low[N],dp[N],W[N],b[N],n,m,et=1,Et,ans[N],as[N],hs[N],mm;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline void dfs(int x,int fa){
    	dep[x]=dep[fa]+1,siz[x]=1,dfn[x]=++tot,f[x][0]=fa;
    	for (rr int i=0;f[x][i];++i) f[x][i+1]=f[f[x][i]][i];
    	for (rr int i=as[x];i;i=e[i].next)
    	    if (e[i].y!=fa) dfs(e[i].y,x),siz[x]+=siz[e[i].y];
    }
    inline signed lca(int x,int y){
    	if (dep[x]<dep[y]) x^=y,y^=x,x^=y;
    	for (rr int i=lg[dep[x]];~i;--i)
    	    if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (rr int i=lg[dep[x]];~i;--i)
    	    if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    	return f[x][0]; 
    }
    inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
    inline void add(int x,int y){E[++Et]=(node){y,hs[x]},W[Et]=dep[y]-dep[x],hs[x]=Et;}
    inline void Insert(int x){
    	if (!tot) {stac[++tot]=x; return;}
    	rr int Lca=lca(x,stac[tot]);
    	while (tot>1&&dep[Lca]<dep[stac[tot-1]]) add(stac[tot-1],stac[tot]),--tot;
    	if (dep[Lca]<dep[stac[tot]]) add(Lca,stac[tot]),--tot;
    	if (stac[tot]!=Lca) stac[++tot]=Lca; stac[++tot]=x;
    }
    inline void dfs1(int x,int fa){
    	dp[x]=1e7;
    	for (rr int i=hs[x];i;i=E[i].next)
    	if (E[i].y!=fa){
    		dfs1(E[i].y,x);
    		if (dp[E[i].y]+W[i]<dp[x]) dp[x]=dp[E[i].y]+W[i],low[x]=low[E[i].y];
    		    else if (dp[E[i].y]+W[i]==dp[x]&&low[x]>low[E[i].y]) low[x]=low[E[i].y];
    	}
    	if (v[x]) dp[x]=0,low[x]=x;
    }
    inline void answ(int x,int fa){
    	rr int x1=x,x2=x;
    	for (rr int i=lg[dep[x1]];~i;--i)
    	    if (dep[f[x1][i]]>dep[fa]) x1=f[x1][i];
    	ans[low[fa]]-=siz[x1];//先把可能影响的点删除
    	for (rr int i=lg[dep[x2]];~i;--i){
    		rr int Bot=dep[x]-dep[f[x2][i]]+dp[x],Top=dep[f[x2][i]]-dep[fa]+dp[fa];
    		if (dep[f[x2][i]]>dep[fa]&&(Bot<Top||(Bot==Top&&low[x]<low[fa]))) x2=f[x2][i];
    	}
    	ans[low[fa]]+=siz[x1]-siz[x2],ans[low[x]]+=siz[x2]-siz[x];//用中间点分开统计贡献
    }
    inline void dfs2(int x,int fa){
    	for (rr int i=hs[x];i;i=E[i].next)
    	if (E[i].y!=fa){
    		if (dp[x]+W[i]<dp[E[i].y]) dp[E[i].y]=dp[x]+W[i],low[E[i].y]=low[x];
    		    else if (dp[x]+W[i]==dp[E[i].y]&&low[E[i].y]>low[x]) low[E[i].y]=low[x];
    		answ(E[i].y,x),dfs2(E[i].y,x);
    	}
    	ans[low[x]]+=siz[x],hs[x]=0;//补回未加入的点
    }
    signed main(){
    	n=iut(),lg[0]=-1;
    	for (rr int i=1;i<=n;++i) lg[i]=lg[i>>1]+1;
    	for (rr int i=1;i<n;++i){
    		rr int x=iut(),y=iut();
    		e[++et]=(node){y,as[x]},as[x]=et;
    		e[++et]=(node){x,as[y]},as[y]=et;
    	}
    	dfs(1,0);
    	for (rr int Q=iut();Q;--Q){
    		mm=m=iut(),tot=Et=0,a[++m]=1;
    		for (rr int i=1;i<m;++i) v[b[i]=a[i]=iut()]=1;
    		sort(a+1,a+1+m,cmp),m=unique(a+1,a+1+m)-a-1;
    		for (rr int i=1;i<=m;++i) Insert(a[i]);
    		for (;tot>1;--tot) add(stac[tot-1],stac[tot]);
    		dfs1(1,0),dfs2(1,0);
    		for (rr int i=1;i<=mm;++i) if (b[i])
    		    print(ans[b[i]]),putchar(i==mm?10:32),ans[b[i]]=0;
    		for (rr int i=1;i<=m;++i) v[a[i]]=0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    sql server delete语句
    sql server 通配符
    sql server join联结
    windows下如何使用两个版本的nodejs
    PHP的Trait 特性
    PHP错误与异常处理try和catch
    laravel belongsTo()&hasOne()用法详解
    Laravel Model 的 fillable (白名单)与 guarded (黑名单)
    js原生,缓动动画封装
    js原生轮播图
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14488036.html
Copyright © 2011-2022 走看看