其他分享
首页 > 其他分享> > 题解 同桌的你

题解 同桌的你

作者:互联网

传送门

基环树上求最大独立边集,且输出方案

题解说最大独立边集的大小可以贪心,但不知所贪
正解是找了个性质
发现在环上任选一条边断掉,如果影响了答案说明这条边一定要选,那和两个端点相连的另外两条边就一定不选
于是可以分别断掉后分别做一次DP,取最大的那个

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;

namespace force{
	bool mp[30][30];
	int bel[50], max1, max2;
	bool vis[50];
	vector<pair<int, int>> v, ans;
	void check() {
		int cnt1=0, cnt2=0;
		for (auto it:v) {
			if (mp[it.fir][it.sec] || mp[it.sec][it.fir]) {
				++cnt1;
				if (bel[it.fir]!=bel[it.sec]) ++cnt2;
			}
		}
		if (cnt1>max1) {
			max1=cnt1, max2=cnt2; ans=v;
		}
		else if (cnt1==max1 && cnt2>max2) {
			max1=cnt1, max2=cnt2; ans=v;
		}
	}
	void dfs(int u) {
		if (u>n) {check(); return ;}
		if (vis[u]) {dfs(u+1); return ;}
		vis[u]=1;
		for (int i=u+1; i<=n; ++i) if (!vis[i]) {
			vis[i]=1; v.push_back(make(u, i));
			dfs(u+1);
			vis[i]=0; v.pop_back();
		}
		vis[u]=0;
	}
	void solve() {
		max1=0; max2=0;
		memset(mp, 0, sizeof(mp));
		memset(bel, 0, sizeof(bel));
		memset(vis, 0, sizeof(vis));
		v.clear(); ans.clear();
		for (int i=1; i<=n; ++i) {
			mp[i][read()]=1; bel[i]=read();
		}
		dfs(1);
		printf("%d %d\n", max1, max2);
		for (auto it:ans) printf("%d %d\n", it.fir, it.sec);
	}
}

namespace task{
	int head[N], size, fa[N], back[N], bel[N];
	bool ring[N], vis[N], vis2[N];
	vector<pair<int, int>> ans2, s1, s2;
	struct edge{int to, next; bool back, vis;}e[N<<1];
	inline void add(int s, int t, int typ) {e[++size].to=t; e[size].back=typ; e[size].next=head[s]; head[s]=size;}
	struct sit{
		int fir, sec;
		sit(){}
		sit(int a, int b):fir(a),sec(b){}
		inline void operator = (pair<int, int> p) {fir=p.fir; sec=p.sec;}
		inline bool operator < (sit b) {return fir==b.fir?sec<b.sec:fir<b.fir;}
		inline sit operator - (sit b) {return sit(fir-b.fir, sec-b.sec);}
		inline sit operator + (sit b) {return sit(fir+b.fir, sec+b.sec);}
		inline void clear() {fir=0; sec=0;}
	}dp[N][2], ans, t1, t2;
	inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
	int dfs1(int u) {
		// cout<<"dfs1: "<<u<<endl;
		vis[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) if (!e[i].back) {
			v = e[i].to;
			if (vis[v]) {ring[u]=1; return v;}
			int tem=dfs1(v);
			if (~tem) ring[u]=1;
			return tem==u?-1:tem;
		}
		return -1;
	}
	void dfs2(int u) {
		// cout<<"dfs2: "<<u<<endl;
		sit dlt(0, 0); int from=-1;
		bool leaf=1;
		for (int i=head[u],v; ~i; i=e[i].next) if (e[i].back && !e[i].vis) {
			v = e[i].to;
			dfs2(v); leaf=0;
			dp[u][1]=dp[u][1]+dp[v][0];
			sit t=dp[v][1]-dp[v][0]+sit(1, bel[v]!=bel[u]);
			if (dlt<t) dlt=t, back[u]=v;
		}
		if (!leaf) dp[u][0]=dp[u][1]+dlt;
		// printf("dp[%d][1]=%d,%d\n", u, dp[u][1].fir, dp[u][1].sec);
		// printf("dp[%d][0]=%d,%d\n", u, dp[u][0].fir, dp[u][0].sec);
	}
	void dfs3(int u, vector<pair<int,int>>& v, int lst) {
		// cout<<"dfs3: "<<u<<' '<<lst<<endl;
		if (lst) v.pb(make(u, lst));
		for (int i=head[u]; ~i; i=e[i].next) if (e[i].back && !e[i].vis) {
			dfs3(e[i].to, v, lst?0:(e[i].to==back[u]?u:0));
		}
	}
	void solve() {
		size=1; ans.clear(); ans2.clear(); t1.clear(); t2.clear();
		memset(head, -1, sizeof(head));
		memset(vis, 0, sizeof(vis));
		memset(vis2, 0, sizeof(vis2));
		memset(ring, 0, sizeof(ring));
		for (int i=1; i<=n; ++i) fa[i]=i;
		for (int i=1,v; i<=n; ++i) {v=read(); add(i, v, 0); add(v, i, 1); bel[i]=read(); fa[find(v)]=find(i);}
		// cout<<"bel: "; for (int i=1; i<=n; ++i) cout<<bel[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) if (!vis2[find(i)]) {dfs1(i); vis2[find(i)]=1;}
		// cout<<"ring: "; for (int i=1; i<=n; ++i) cout<<ring[i]<<' '; cout<<endl;
		memset(vis, 0, sizeof(vis));
		for (int u=1; u<=n; ++u) if (ring[u] && !vis[find(u)]) {
			// cout<<"u: "<<u<<endl;
			int e1, e2, v;
			s1.clear(); s2.clear();
			for (int i=head[u],v; ~i; i=e[i].next) if (!e[i].back && ring[e[i].to]) {e1=i; e[e1].vis=e[e1^1].vis=1; break;}
			memset(dp, 0, sizeof(dp)); memset(back, -1, sizeof(back));
			// cout<<"e1: "<<e1<<' '<<e[e1].to<<endl;
			v=e[e1].to;
			dfs2(u); dfs3(u, s1, 0); t1=dp[u][0];
			e[e1].vis=e[e1^1].vis=0;
			// cout<<"v: "<<v<<endl;
			for (int i=head[v]; ~i; i=e[i].next) if (!e[i].back && ring[e[i].to]) {e2=i; e[e2].vis=e[e2^1].vis=1; break;}
			memset(dp, 0, sizeof(dp)); memset(back, -1, sizeof(back));
			dfs2(v); dfs3(v, s2, 0); t2=dp[v][0];
			e[e2].vis=e[e2^1].vis=0;
			if (t1<t2) swap(t1, t2), swap(s1, s2);
			// cout<<"s1: "; for (auto it:s1) cout<<it.fir<<','<<it.sec<<' '; cout<<endl;
			// cout<<"s2: "; for (auto it:s2) cout<<it.fir<<','<<it.sec<<' '; cout<<endl;
			ans=ans+t1; for (auto it:s1) ans2.pb(it);
			vis[find(u)]=1;
		}
		printf("%d %d\n", ans.fir, ans.sec);
		for (auto it:ans2) printf("%d %d\n", it.fir, it.sec);
		// for (int i=1; i<=ans.fir; ++i) puts("0 0");
	}
}

signed main()
{
	freopen("deskmate.in", "r", stdin);
	freopen("deskmate.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read();
		// force::solve();
		task::solve();
	}
	
	return 0;
}

标签:fir,int,题解,同桌,sec,cnt2,cnt1,define
来源: https://www.cnblogs.com/narration/p/15354200.html