首页 > 其他分享 >题解 LGP2607【[ZJOI2008] 骑士】

题解 LGP2607【[ZJOI2008] 骑士】

时间:2022-11-23 15:47:46浏览次数:49  
标签:head LGP2607 int 题解 cnt 基环树 add ZJOI2008 include

problem

基环树森林带权最大独立集。\(n\leq 10^6\)。

solution 0

这里先解释一下基环树森林,它就是一个 \(n\) 个点 \(n\) 条边的森林,同时是一个荒漠

我们拿出其中一棵连通的基环树,它有恰好一个环,每个环上延伸出去一棵子树。我们断掉环上的任意一条边,基环树就变成了树。

基环树可以看作是仙人掌,因此我们可以将题意转化为仙人掌最大独立集

solution 1

考虑每个连通块。

考虑一个连通块,我们找到了一个环。然后断掉环上的任意一条边。

然后以断掉的边为两个根分别跑两遍树形 DP,最后假如断了 \((u,v)\),我们取 \(\max(f_{u,0},g_{v,0})\),即强制根不选的答案。

code

说起来太简单了!

点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include <functional>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
template<int N,int M,class T=int> struct graph{
	int head[N+10],nxt[M*2+10],cnt;
	struct edge{
		int u,v; T w;
		edge(int u=0,int v=0,T w=0):u(u),v(v),w(w){}
	} e[M*2+10];
	edge& operator[](int i){return e[i];}
	graph(){memset(head,cnt=0,sizeof head);}
	void add(int u,int v,int w=0){e[++cnt]=edge(u,v,w),nxt[cnt]=head[u],head[u]=cnt;}
	void link(int u,int v,int w=0){add(u,v,w),add(v,u,w);}
};
int n,w[1000010];
graph<1000010,1000010> g; 
bool vis[1000010],sit[1000010<<1];//vis 判点,sit 判边 
int find_cycle(int u,int p=0){
	vis[u]=1;
	for(int i=g.head[u];i;i=g.nxt[i]){
		int v=g[i].v; if((i^p)==1) continue;
		if(vis[v]) return i;
		if(int res=find_cycle(v,i)) return res;
	}
	return 0;
}
LL dp(int e){//强制不选 s 
//	int s=g[e].u,t=g[e].v;
	function<pair<LL,LL>(int,int)> dfs=[&](int u,int f)->pair<LL,LL>{
		pair<LL,LL> ans={0,w[u]}; vis[u]=1;
		for(int i=g.head[u];i;i=g.nxt[i]){
			int v=g[i].v; if(v==f||(i^e)<=1) continue;
			pair<LL,LL> res=dfs(v,u);
			ans.first+=max(res.first,res.second);
			ans.second+=res.first;
		}
		return ans;
	};
	return dfs(g[e].u,0).first;
}
int main(){
//	#ifdef LOCAL
//	 	freopen("input.in","r",stdin);
//	#endif
	scanf("%d",&n),g.add(0,0);
	for(int u=1,v;u<=n;u++) scanf("%d%d",&w[u],&v),g.link(u,v);
	LL ans=0;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			int e=find_cycle(i);
			ans+=max(dp(e),dp(e^1));
		}
	}
	printf("%lld\n",ans);
	return 0;
}

标签:head,LGP2607,int,题解,cnt,基环树,add,ZJOI2008,include
From: https://www.cnblogs.com/caijianhong/p/solution-P2607.html

相关文章

  • Codeforces Round #835 (Div.4) A-G题解
    原题链接:https://codeforces.com/contest/1744A.MediumNumber题意:给定三个数,求中间那个数(倒数第二小or倒数第二大)。题解:直接用数组存,sort一下输出中间的数即可。#in......
  • 题解 LGP7489【「Stoi2031」手写的从前】
    problem令\(f_0(S)=\dfrac{\sigma(S)}{\pi(S)}\),\(f_k(S)=\sum\limits_{T\subseteqS}f_{k-1}(T)\)。其中\(\sigma(S)=\sum\limits_{x\inS}x\)为\(S\)中所有元素......
  • 【题解】P2303 [SDOI2012] Longge 的问题
    【题解】P2303[SDOI2012]Longge的问题题目链接求\(\displaystyle\sum_{i=1}^n\gcd(i,n)\)将这个柿子展开变复杂,得到\[\displaystyle\sum_{i=1}^{n}\sum_{d\mid......
  • P2819 图的m着色问题 C++ 详细题解
    题目背景给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的。图......
  • P1002 过河卒 详细题解 搜索回溯+递归 [NOIP2002 普及组]
    题目描述棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方......
  • Could not get a resource from the pool 问题解决
    Couldnotgetaresourcefromthepool问题解决今天测试项目的时候,界面提示Couldnotgetaresourcefromthepool 报错信息。登录后台,查询对应的java报错日志报......
  • 奇怪的主席树题 题解
    前言前置知识:可持久化线段树,字符串hash,线段树二分。Description给你一棵\(n\)个点以\(1\)为根节点的树,每一个节点都代表一个\(m\)个字符的字符串。每一个节点......
  • BZOJ1036-[ZJOI2008]树的统计Count&&POJ3237-Tree
    为什么把这两题放在一起呢,因为这两题其实是一道题,只是输入顺序不一样。这里主要以BZOJ1036为例。1036:[ZJOI2008]树的统计CountTimeLimit: 10Sec  MemoryLimit: ......
  • YACS 2022年11月月赛 乙组 T1 数对统计 题解
    好久没更了,闲话一句,我的初赛成绩只有$71.5$,$76$才能进$NOIP$,所以就更一篇吧首先先考虑暴力算法,枚举两个数,设这两个数为$x$和$y$,如果$f[x][y]=false$,那就标记为$t......
  • Vscode/Sublime C++ 打印中文乱码问题解决
    #include<iostream>usingnamespacestd;#ifdef_WIN32#include<windows.h>#endifintmain(){#ifdef_WIN32//控制台显示乱码纠正SetConsoleOutp......