• BZOJ 2286 [Sdoi2011]消耗战


    题解:对询问点建立虚树

    然后在虚树上Dp

    每个点父边边权为这个点到根的边权最小值

    一开始学了假的虚树

    一开始竟然没想到父边边权可以这样赋

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn=500009;
    const int inf=2000000000;
    typedef long long Lint;
    
    int n,m,T;
    
    int cntedge;
    int head[maxn];
    int to[maxn],nex[maxn],dist[maxn];
    void Addedge(int x,int y,int z){
    //	cout<<x<<' '<<y<<' '<<z<<endl;
    	nex[++cntedge]=head[x];
    	to[cntedge]=y;
    	dist[cntedge]=z;
    	head[x]=cntedge;
    }
    
    int dfsclock;
    int father[maxn],depth[maxn],minedge[maxn];
    int L[maxn],R[maxn];
    void Dfs(int now,int fa,int ecost){
    	L[now]=++dfsclock;
    	father[now]=fa;
    	depth[now]=depth[fa]+1;
    	minedge[now]=min(minedge[fa],ecost);
    	
    	for(int i=head[now];i;i=nex[i]){
    		if(to[i]==fa)continue;
    		Dfs(to[i],now,dist[i]);
    	}
    	R[now]=++dfsclock;
    }
    
    int f[maxn][20];
    void LCAinit(){
    	for(int i=1;i<=n;++i)f[i][0]=father[i];
    	for(int j=1;j<=19;++j){
    		for(int i=1;i<=n;++i){
    			f[i][j]=f[f[i][j-1]][j-1];
    		}
    	}
    }
    int Getlca(int u,int v){
    	if(depth[u]<depth[v])swap(u,v);
    	for(int j=19;j>=0;--j){
    		if(depth[f[u][j]]>=depth[v])u=f[u][j];
    	}
    	if(u==v)return u;
    	for(int j=19;j>=0;--j){
    		if(f[u][j]!=f[v][j]){
    			u=f[u][j];v=f[v][j];
    		}
    	}
    	return f[u][0];
    }
    
    int h[maxn];
    int ene[maxn];
    int cmp(const int &rhs1,const int &rhs2){
    	return L[rhs1]<L[rhs2];
    }
    
    int S[maxn],top;
    inline int intree(int x,int y){
    	return (L[x]>=L[y])&&(R[x]<=R[y]);
    }
    
    
    Lint g[maxn];
    int q[maxn];
    void Dp(int x,int fa){
    	if(ene[x]){
    		q[x]=1;g[x]=inf;return;
    	}
    	q[x]=g[x]=0;
    	for(int i=head[x];i;i=nex[i]){
    		if(to[i]==fa)continue;
    		Dp(to[i],x);
    		q[x]|=q[to[i]];
    		if(q[to[i]])g[x]+=min(g[to[i]],dist[i]*1LL);
    	}
    }
    
    int Xsize;
    int a[maxn];
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n-1;++i){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		Addedge(x,y,z);
    		Addedge(y,x,z);
    	}
    	
    	minedge[0]=inf;
    	Dfs(1,0,inf);
    	LCAinit();
    	
    	memset(head,0,sizeof(head));
    	scanf("%d",&T);
    	while(T--){
    //		cout<<"begin"<<endl;
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i){
    			scanf("%d",&h[i]);ene[h[i]]=1;
    		}
    		sort(h+1,h+1+n,cmp);
    //		for(int i=1;i<=n;++i)cout<<h[i]<<' ';
    //		cout<<endl;
    		cntedge=Xsize=0;
    		S[top=1]=1;a[++Xsize]=1;
    		for(int i=1;i<=n;++i){
    			int lca=Getlca(h[i],S[top]);
    			while(!intree(h[i],S[top])){
    				if(intree(lca,S[top-1])){
    					Addedge(lca,S[top],minedge[S[top]]);--top;break;
    				}
    				Addedge(S[top-1],S[top],minedge[S[top]]);--top;
    			}
    			if(S[top]!=lca){
    				S[++top]=lca;a[++Xsize]=lca;
    			}
    			S[++top]=h[i];a[++Xsize]=h[i];
    		}
    		while(top>1){
    			Addedge(S[top-1],S[top],minedge[S[top]]);--top;
    		}
    		Dp(1,0);
    		printf("%lld
    ",g[1]);
    		for(int i=1;i<=Xsize;++i){
    			ene[a[i]]=head[a[i]]=0;
    		}
    	}
    	return 0;
    }
    

      

    自己还是太辣鸡了
  • 相关阅读:
    phpmailer发送邮件,可以带附件
    poj 3370 鸽笼原理知识小结
    yii_wiki_145_yii-cjuidialog-for-create-new-model (通过CJuiDialog来创建新的Model)
    兄弟单词查询
    asp.net mvc3 利用Ajax实现局部刷新
    eclipse 找不到application选项
    ECharts一个强大的商业产品图表库
    多校训练hdu --Nice boat(线段树,都是泪)
    [外文理解] DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构。
    ubuntu重新启动网卡
  • 原文地址:https://www.cnblogs.com/zzyer/p/8455517.html
Copyright © 2020-2023  润新知