• #虚树,树形dp#洛谷 4103 [HEOI2014]大工程


    题目


    分析

    建一棵虚树,然后树形dp,维护最长/短链和次长/短链,
    对于第一个就是统计每条边有多少个点对经过就可以了


    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm> 
    #define rr register
    using namespace std;
    const int N=1000011; long long ans1; int ans2,a[N],ans3,mm;
    struct node{int y,next;}e[N<<1],E[N]; int stac[N],hs[N],mn[N][2],mx[N][2],v[N];
    int dep[N],fat[N],siz[N],as[N],Siz[N],W[N],big[N],dfn[N],tot,Top[N],n,et=1,Et,m;
    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 dfs1(int x,int fa){
    	dep[x]=dep[fa]+1,fat[x]=fa,siz[x]=1;
    	for (rr int i=as[x],SIZ=-1;i;i=e[i].next)
    	if (e[i].y!=fa){
    		dfs1(e[i].y,x),siz[x]+=siz[e[i].y];
    		if (SIZ<siz[e[i].y]) big[x]=e[i].y,SIZ=siz[e[i].y];
    	}
    }
    inline void dfs2(int x,int linp){
    	dfn[x]=++tot,Top[x]=linp;
    	if (!big[x]) return; dfs2(big[x],linp);
    	for (rr int i=as[x];i;i=e[i].next)
    	if (e[i].y!=big[x]&&e[i].y!=fat[x])
    	    dfs2(e[i].y,e[i].y);
    }
    inline signed lca(int x,int y){
    	while (Top[x]^Top[y]){
    		if (dep[Top[x]]<dep[Top[y]]) x^=y,y^=x,x^=y;
    		x=fat[Top[x]];
    	}
    	if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
    	return x;
    }
    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 signed min(int a,int b){return a<b?a:b;}
    inline signed max(int a,int b){return a>b?a:b;}
    inline void dfs(int x){
    	mn[x][0]=v[x]?0:1e9,mn[x][1]=1e9,
    	mx[x][0]=v[x]?0:-1e9,mx[x][1]=-1e9,Siz[x]=v[x];
    	for (rr int i=hs[x];i;i=E[i].next){
    		dfs(E[i].y),Siz[x]+=Siz[E[i].y];
    		if (mn[x][0]>mn[E[i].y][0]+W[i])
    			mn[x][1]=mn[x][0],mn[x][0]=mn[E[i].y][0]+W[i];
    		else if (mn[x][1]>mn[E[i].y][0]+W[i])
    		    mn[x][1]=mn[E[i].y][0]+W[i];
    		if (mx[x][0]<mx[E[i].y][0]+W[i])
    			mx[x][1]=mx[x][0],mx[x][0]=mx[E[i].y][0]+W[i];
    		else if (mx[x][1]>mx[E[i].y][0]+W[i])
    		    mx[x][1]=mx[E[i].y][0]+W[i];
    		ans2=min(ans2,mn[x][0]+mn[x][1]);
    		ans3=max(ans3,mx[x][0]+mx[x][1]);
    		ans1+=1ll*(mm-Siz[E[i].y])*Siz[E[i].y]*W[i];
    	}
    	hs[x]=0;
    }
    signed main(){
    	n=iut();
    	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;
    	}
    	dfs1(1,0),dfs2(1,1);
    	for (rr int Q=iut();Q;--Q){
    		m=iut(),mm=m,tot=Et=0,a[++m]=1;
    		for (rr int i=1;i<m;++i) v[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]);
    		ans1=0,ans2=1e9,ans3=0,dfs(1);
    		for (rr int i=1;i<=m;++i) v[a[i]]=0;
    		printf("%lld %d %d
    ",ans1,ans2,ans3);
    	}
    	return 0;
    }
    
  • 相关阅读:
    aspcms产品详情页调取相关产品
    构造函数中返回一个对象对结果有什么影响
    跨域的几种方法及案例代码
    localStorage兼容方案
    H5 拖放事件详解
    由作用域安全的构造函数想到的
    valueOf和toString的区别
    网页布局--自适应
    【MongoDB系列】简介、安装、基本操作命令
    【JavaWeb】之Servlet
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14025047.html
走看看 - 开发者的网上家园