• [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;
    }
    
  • 相关阅读:
    xmind 8 readme
    【08】英语词汇速记大全1词根词缀记忆法
    【20180312】2018年03月12日(随想)
    大佬说
    github私有库购买信息
    【01】用构造器创建函数中的小知识
    【01】魔芋使用MDN的一点点经验
    10.12 telnet:远程登录主机
    10.11 arping:发送arp请求
    10.10 traceroute:追踪数据传输路由状况
  • 原文地址:https://www.cnblogs.com/void-f/p/8678092.html
Copyright © 2020-2023  润新知