zoukankan      html  css  js  c++  java
  • 【bzoj1040】 ZJOI2008—骑士

    http://www.lydsy.com/JudgeOnline/problem.php?id=1040 (题目链接)

    题意

      一个基环森林,从中选出不相邻的若干个点使得这些点的点权和最大。

    Solution

      把树做完以后枚举环上一点选和不选,两者取个最值就可以了。多个连通块的情况用并查集搞一下。

    细节

      开LL

    代码

    // bzoj1040
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=1000010;
    LL f[maxn][2],t[maxn][2],ans;
    int head[maxn],dag[maxn],vis[maxn],fa[maxn],p[maxn],a[maxn],w[maxn],cnt,n,m;
    struct edge {int to,next;}e[maxn<<1];
    
    void link(int u,int v) {
    	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    void topsort() {
    	queue<int> q;
    	for (int i=1;i<=n;i++) if (dag[i]==1) q.push(i);
    	while (!q.empty()) {
    		int x=q.front();q.pop();dag[x]--;
    		for (int i=head[x];i;i=e[i].next)
    			if (dag[e[i].to]>1) if (--dag[e[i].to]==1) q.push(e[i].to);
    	}
    }
    void dfs(int x,int fa) {
    	f[x][1]=w[x],f[x][0]=0;
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !dag[e[i].to]) {
    			dfs(e[i].to,x);
    			f[x][1]+=f[e[i].to][0];
    			f[x][0]+=max(f[e[i].to][1],f[e[i].to][0]);
    		}
    }
    void find(int x,int fa) {
    	a[++m]=x;vis[x]=1;
    	for (int i=head[x];i;i=e[i].next)
    		if (!vis[e[i].to] && dag[e[i].to]) find(e[i].to,x);
    }
    int find(int x) {
    	return x==fa[x] ? x : fa[x]=find(fa[x]);
    }
    LL dp(int x) {
    	LL res=0;
    	m=0;find(x,0);
    	t[1][1]=f[a[1]][1];t[1][0]=0;
    	t[2][1]=0;t[2][0]=f[a[1]][1]+f[a[2]][0];
    	for (int i=3;i<m;i++) {
    		t[i][0]=max(t[i-1][1],t[i-1][0])+f[a[i]][0];
    		t[i][1]=t[i-1][0]+f[a[i]][1];
    	}
    	res=max(res,max(t[m-1][1],t[m-1][0])+f[a[m]][0]);
    	t[1][1]=0;t[1][0]=f[a[1]][0];
    	for (int i=2;i<=m;i++) {
    		t[i][0]=max(t[i-1][1],t[i-1][0])+f[a[i]][0];
    		t[i][1]=t[i-1][0]+f[a[i]][1];
    	}
    	return max(res,max(t[m][1],t[m][0]));
    }
    int main() {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) fa[i]=i;
    	for (int u,i=1;i<=n;i++) {
    		scanf("%d%d",&w[i],&u);
    		link(i,u);dag[i]++,dag[u]++;
    		if (find(i)!=find(u)) fa[find(i)]=find(u);
    	}
    	topsort();
    	for (int i=1;i<=n;i++) if (dag[i]) {
    			p[find(i)]=i;
    			dfs(i,0);
    		}
    	for (int i=1;i<=n;i++) if (p[i]) ans+=dp(p[i]);
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    vb 使用Cystal Reports 9小例子
    VB Export sample
    c++文件結束符
    初学PHP:用post传递checkbox
    VB 图片在数据库的导入与导出
    vb 事务sample
    linux查找进程并杀掉进程
    WebRequest 对象的使用
    Asp操作Cookies(设置[赋值]、读取、删除[设置过期时间])
    .net webrequest应用
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6525449.html
Copyright © 2011-2022 走看看