• [ZJOI2008] 骑士


    [ZJOI2008] 骑士

    BZOJ
    luogu
    我们发现关系图由恰好n个点,n条边构成,
    这告诉我们关系图是一些基环树,
    我们可以找出这个环,对环上每个点的子树dp一遍
    再把这个环dp一遍求出答案
    树dp:设(f_i)表示选择i的子树最大价值和
    (g_i)表示不选i的子树最大价值和

    [f_u+=g_v$$$$g_u+=max(f_v,g_v) ]

    环dp:相同的状态和转移,讨论是否选1做两遍dp
    博猪抠环的方法好像复杂了,不过过了就懒得管了...
    注意图不一定连通和有重边

    #define ll long long
    #include<bits/stdc++.h>
    using namespace std;
    const int _=1e6+5;
    int re(){
    	int x=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    int n,cnt,tot,top,sz,ts;
    int h[_],cir[_],st[_],fa[_],dfn[_],low[_],tmp[_];
    ll Ans,ans,g[_],f[_],F[_],G[_];
    bool vis[_];
    struct edge{int to,next;}e[_<<1];
    void link(int u,int v){
    	e[++cnt]=(edge){v,h[u]};h[u]=cnt;
    	e[++cnt]=(edge){u,h[v]};h[v]=cnt;
    }
    void tarjan(int u){
    	dfn[u]=low[u]=++ts;st[++top]=u;
    	for(int i=h[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    			if(low[v]>=dfn[u]){
    				int x;sz=0;
    				do{x=st[top--];tmp[++sz]=x;}while(x^v);tmp[++sz]=u;
    				if(sz>tot){tot=sz;for(int j=1;j<=sz;j++)cir[j]=tmp[j];}
    			}
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    void dfs(int u){
    	for(int i=h[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(vis[v]||v==fa[u]||fa[v]==u)continue;//重边
    		fa[v]=u;dfs(v);f[u]+=g[v];g[u]+=max(f[v],g[v]);
    	}
    }
    int main(){
    	n=re();
    	for(int i=1;i<=n;i++){
    		f[i]=re();link(i,re());
    	}
    	for(int i=1;i<=n;i++){
    		if(dfn[i])continue;
    		top=0;tot=0;tarjan(i);
    		for(int j=1;j<=tot;j++)vis[cir[j]]=1;
    		for(int j=1;j<=tot;j++){
    			dfs(cir[j]);F[j]=f[cir[j]];G[j]=g[cir[j]];
    		}
    		G[2]+=F[1];F[3]+=G[2];G[3]+=G[2];//选择1
    		for(int j=4;j<=tot;j++){
    			F[j]+=G[j-1];
    			G[j]+=max(F[j-1],G[j-1]);
    		}
    		ans=G[tot];
    		for(int j=1;j<=tot;j++){
    			F[j]=f[cir[j]];G[j]=g[cir[j]];
    		}
    		F[2]+=G[1];G[2]+=G[1];//不选择1
    		for(int j=3;j<=tot;j++){
    			F[j]+=G[j-1];
    			G[j]+=max(F[j-1],G[j-1]);
    		}
    		ans=max(ans,max(F[tot],G[tot]));
    		Ans+=ans;
    	}
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    PAT:循环-12. 打印九九口诀表(15) AC
    PAT:循环-07. 爬动的蠕虫(15) 错两个
    PAT:循环-01. 求整数段和(15) AC
    PAT:分支-16. 计算分段函数(10) AC
    PAT:分支-10. 计算个人所得税(10) AC
    PAT:分支-08. 高速公路超速处罚(15) AC
    UIToolBar
    iOS 代码实现获得应用的版本号(Version/Build)
    IOS开发之 ---- iOS8中提示框的使用UIAlertController(UIAlertView和UIActionSheet二合一)
    IOS开发中的CGFloat、CGPoint、CGSize和CGRect
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/9863145.html
Copyright © 2020-2023  润新知