zoukankan      html  css  js  c++  java
  • [Bzoj3611]大工程(虚树+DP)

    Description

    题目链接

    Solution

    在虚树上跑DP即可

    关于虚树的建立,是维护一个最右链的过程

    关键代码如下:

    sort(A+1,A+k+1,cmp);//按dfs序排序
    s[top=1]=1;//栈维护最右链
    for(int i=1;i<=k;++i){
    	int t=A[i],f=0;
    	while(top){
    		f=LCA(A[i],s[top]);
    		if(top>1&&dep[f]<dep[s[top-1]])
    			Link(s[top-1],s[top]),top--;
    		else if(dep[f]<dep[s[top]]){Link(f,s[top--]);break;}
    		else break;
    	}
    	if(s[top]!=f) s[++top]=f;
    	s[++top]=t;
    }
    while(--top) Link(s[top],s[top+1]);
    

    Code

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define Inf 0x7fffffff
    #define ll long long
    #define N 1000010
    using namespace std;
    
    struct info{int to,nex,w;}e[N*4];
    int n,tot,head[N],dfn[N],fa[N][20],_log,dep[N],A[N],mn[N],mx[N];
    bool b[N];
    ll Ans1,Ans2,f[N],size[N],sum;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        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;
    }
    
    inline void Link(int u,int v){
    	if(u==v) return;
    	e[++tot].to=v;e[tot].nex=head[u];head[u]=tot;e[tot].w=dep[v]-dep[u];
    }
    
    void dfs(int u,int pre){
    	dfn[u]=++tot;
    	for(int i=1;i<=_log;++i) 
    		fa[u][i]=fa[fa[u][i-1]][i-1];
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==pre) continue;
    		dep[v]=dep[u]+1;
    		fa[v][0]=u;
    		dfs(v,u);
    	}
    	head[u]=0;
    }
    
    int LCA(int u,int v){
        if(dep[u]>dep[v]) swap(u,v);
        int d=dep[v]-dep[u];
        
        for(int i=0;i<=_log;++i)
            if(d&(1<<i)) v=fa[v][i];
        if(u==v) return v;
        
        for(int i=_log;i>=0;--i)
            if(fa[u][i]!=fa[v][i]){
                u=fa[u][i];
                v=fa[v][i];
            }
        return fa[u][0];
    }
    
    
    bool cmp(int a,int b){return dfn[a]<dfn[b];}
    int s[N],top;
    void bulid(){
    	int k=read();for(int i=1;i<=k;++i) b[A[i]=read()]=1;
    	sort(A+1,A+k+1,cmp);
    	s[top=1]=1;
    	for(int i=1;i<=k;++i){
    		int t=A[i],f=0;
    		while(top){
    			f=LCA(A[i],s[top]);
    			if(top>1&&dep[f]<dep[s[top-1]])
    				Link(s[top-1],s[top]),top--;
    			else if(dep[f]<dep[s[top]]){Link(f,s[top--]);break;}
    			else break;
    		}
    		if(s[top]!=f) s[++top]=f;
    		s[++top]=t;
    	}
    	while(--top) Link(s[top],s[top+1]);
    }
    
    void dp(int u){
    	size[u]=b[u];
    	f[u]=0;
    	mn[u]=b[u]?0:Inf;
    	mx[u]=b[u]?0:-Inf;
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		dp(v);
    		sum+=(f[u]+size[u]*e[i].w)*size[v]+f[v]*size[u];
    		size[u]+=size[v];
    		f[u]+=f[v]+e[i].w*size[v];
    		Ans1=min(Ans1,(ll)mn[u]+mn[v]+e[i].w);
    		Ans2=max(Ans2,(ll)mx[u]+mx[v]+e[i].w);
    		mn[u]=min(mn[u],mn[v]+e[i].w);
    		mx[u]=max(mx[u],mx[v]+e[i].w);
    	}
    	head[u]=0;
    }
    
    int main(){
    	n=read();_log=log(n)/log(2);
    	for(int i=1;i<n;++i){
    		int u=read(),v=read();
    		Link(u,v);Link(v,u);
    	}
    	tot=0;dfs(1,0);
    	int q=read();
    	while(q--){
    		bulid();
    		Ans1=1e16,Ans2=-1e16,sum=0;
    		dp(1);
    		printf("%lld %lld %lld
    ",sum,Ans1,Ans2);
    		memset(b,0,sizeof(b));
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ 1953 World Cup Noise
    POJ 1995 Raising Modulo Numbers (快速幂取余)
    poj 1256 Anagram
    POJ 1218 THE DRUNK JAILER
    POJ 1316 Self Numbers
    POJ 1663 Number Steps
    POJ 1664 放苹果
    如何查看DIV被设置什么CSS样式
    独行DIV自适应宽度布局CSS实例与扩大应用范围
    python 从入门到精通教程一:[1]Hello,world!
  • 原文地址:https://www.cnblogs.com/void-f/p/8678092.html
Copyright © 2011-2022 走看看