首页 > 代码库 > BZOJ 1854: [Scoi2010]游戏 [连通分量 | 并查集 | 二分图匹配]
BZOJ 1854: [Scoi2010]游戏 [连通分量 | 并查集 | 二分图匹配]
题意:
有$n \le 10^6$中物品,每种两个权值$\le 10^4$只能选一个,使得选出的所有权值从1递增,最大递增到多少
一开始想了一个奇怪的规定流量网络流+二分答案做法...然而我还不知道怎么规定流量...并且一定会T
然后发现题解中二分图匹配用了匈牙利,可以从小到大找增广路,貌似比较科学
然后发现还有用并查集的,看到“权值是点,装备是边”后突然灵机一动想到一个dfs做法
每个边的两个点可以选择一个
找出每个连通分量,如果里面有环或重边那么这里面所有点都可以选
如果是树的话,必须放弃一个点(当然是最大点),除非有的点在别的连通分量里选过了
$O(n)$,不带$\alpha$的啦,然而常数大所以并不比并查集快
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int N=1e4+5, M=1e6+5;typedef long long ll;inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f;}int n, m, u, v;struct edge{int v, ne;} e[M<<1];int cnt=1, h[N];inline void ins(int u, int v) { e[++cnt]=(edge){v, h[u]}; h[u]=cnt; e[++cnt]=(edge){u, h[v]}; h[v]=cnt;}int vis[N], q[N], p, circle, flag[N];int ve[M<<1];void dfs(int u) { vis[u]=1; q[++p]=u; for(int i=h[u];i;i=e[i].ne) if(!ve[i]){ ve[i] = ve[i^1] = 1; if(!vis[e[i].v]) dfs(e[i].v); else circle=1; }}int main() { freopen("in","r",stdin); m=read(); for(int i=1; i<=m; i++) u=read(), v=read(), n=max(n, max(u, v)), ins(u, v); for(int i=1; i<=n; i++) if(!vis[i]) { p=0; circle=0; dfs(i); int mx=0; for(int i=1; i<=p; i++) { if(flag[q[i]]) circle = 1; else flag[q[i]] = 1; mx = max(mx, q[i]); } if(!circle) flag[mx] = 0; } int ans = 0; while(flag[ans+1]) ans++; printf("%d",ans);}
BZOJ 1854: [Scoi2010]游戏 [连通分量 | 并查集 | 二分图匹配]
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。