ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

A层省选3

2022-08-12 21:30:24  阅读:120  来源: 互联网

标签:层省 int long maxn ull printf include


A. 定位系统

不会,又是\(lct\),三场连着考,我该学学了。。

还有好多知识点没学,联赛前还想多刷点思维题,,,,,,难受

扔个暴力吧,找个度大于等于三的做根,然后记录一个点的子树内是否有发射器,当某个点有多于\(1\)棵子树没有发射器时,设置发射器到只剩一个没有的子树

除了找根为啥找度大于等于三的都比较好理解

然后就是\(lct\)啥的维护,这里扔个暴力跑路

LINK-CUT-TREE
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<random>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rd((ull)(new char) * (ull)(new char));
inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x;
}
const int maxn = 500005;
int n, q;
int fa[maxn], ans, have[maxn], nohave[maxn];
bool flag[maxn];
vector<int>g[maxn];

void dfs(int x){
	flag[x] = nohave[x] = have[x] = 0;
	for(int v : g[x]){
		if(v == fa[x] || v == 0)continue;
		fa[v] = x;
		dfs(v);
		if(!flag[v]) ++nohave[x];
		else ++have[x];
	}
	if(nohave[x] > 1){
		ans += nohave[x] - 1;
		flag[x] = 1;
	}
	if(have[x])flag[x] = 1;
	// printf("dfs:%d %d %d\n",x ,have[x], nohave[x]);
}
int rd[maxn];
void LINK(int u, int v){
	g[u].push_back(v);
	g[v].push_back(u);
	++rd[u]; ++rd[v];
}
void CUT(int u, int v){
	int su = g[u].size();
	for(int i = 0; i < su; ++i)if(g[u][i] == v){g[u][i] = 0; break;}
	int sv = g[v].size();
	for(int i = 0; i < sv; ++i)if(g[v][i] == u){g[v][i] = 0; break;}
	--rd[u]; --rd[v];
}
void TREE(){
	if(n == 1)ans = 0;
	else{
		ans = 0; int root = -1;
		for(int i = 1; i <= n; ++i)if(rd[i] >= 3){root = i;break;}
		if(root == -1)ans = 1;
		else{fa[root] = 0; dfs(root);}
	}
	printf("%d\n",ans);
}
int main(){
	freopen("location.in","r",stdin);
	freopen("location.out","w",stdout);
	n = read();
	for(int i = 1; i < n; ++i){
		int u = read(), v = read();
		LINK(u, v);
	}
	TREE();
	int q = read();
	for(int i = 1; i <= q; ++i){
		int u = read(), v = read(), x = read(), y = read();
		CUT(u, v);LINK(x, y);TREE();
	}
	return 0;
}

签到题

分类处理,最小割只可能为\(0, 1 , 2 , 3\)

\(0\)不用管

\(1\)\(tarjan\)找桥

剩下的只能是\(2/3\)考虑如果\(mincut(a, b) == 3 mincut(b,c) == 3,mincut(a,c)\)一定不能是\(2\)那么最小割为\(3\)的构成了一些等价类,(或者说是集合?)

我们把搜索树搞出来,如果最小割为\(2\)那么要么是两个树边要么是一个树边一个非树边

我们给非树边一个随机数,树边设成经过他的非树边的异或和

如果一个树边和一个非树边相同,那么我们可以一个树边一个非树边割掉

如果两个树边相同,我们可以割掉他们(他们一定是树上的祖孙关系(连在一个点上下))

讲不太明白,自己画画图吧,代码还有一点注释

code
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000005;
const int maxm = 3000005;
inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x;
}
mt19937_64 rd((ull)(new char) * (ull)(new char));
int n, m, head[maxn], tot;
struct edge{int to, net;}e[maxm << 1 | 1];
void add(int u, int v){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
}
struct SET{
	int f[maxn];
	void init(){for(int i = 1; i <= n; ++i)f[i] = i;}
	int fa(int x){return f[x] == x ? x : f[x] = fa(f[x]);}
	void merge(int u, int v){
		u = fa(u); v = fa(v);
		if(u != v)f[v] = u;
	}
}s;
ll ans;
int vis[maxn], dfn[maxn], low[maxn], tim, sta[maxn], top;
int block, belong[maxn],size[maxn];
void tarjan(int x, int fa){
	dfn[x] = low[x] = ++tim;
	sta[++top] = x; vis[x] = 1;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == fa)continue;
		if(!dfn[v]){
			tarjan(v, x);
			low[x] = min(low[x], low[v]);
		}else if(vis[v])low[x] = min(low[x], dfn[v]);
	}
	if(dfn[x] == low[x]){
		int si = 0, y;
		++block;
		do{
			++si;
			y = sta[top--];
			belong[y] = block;
			vis[y] = 0;
		}while(y != x);
		ans += 1ll * size[s.fa(x)] * si;
		size[s.fa(x)] += si;
	}
}
bool del[maxm], flag[maxn];
gp_hash_table<ull, bool>mp;//非树边颜色记录
gp_hash_table<ull, int>h, rcol;
int now;
ull col[maxn], val[maxn];
int dep[maxn], fa[maxn];
void dfs1(int x){//处理dep,fa基本信息,对非树边赋随机值进行树上差分
	for(int i = head[x]; i; i = e[i].net)
	 	if(!del[i]){
			 int v = e[i].to;
			 if(v == fa[x])continue;
			 if(vis[v] != now){
				 dep[v] = dep[x] + 1;
				 vis[v] = now;
				 fa[v] = x;
				 dfs1(v);
			 }else if(dep[v] < dep[x]){
				 ull sr = rd();
				 mp[sr] = 1;//非树边
				 col[v] ^= sr;
				 col[x] ^= sr;
			 }
		 }
}
void dfs2(int x){//处理树上差分,得到边的真实值
	for(int i =  head[x]; i; i = e[i].net)
		if(!del[i]){
			int v = e[i].to;
			if(v == fa[x])continue;
			if(vis[v] != now){
				vis[v] = now;
				dfs2(v);
				col[x] ^= col[v];
				if(mp.find(col[v]) != mp.end())val[v] ^= rd();//如果与某个非树边颜色相同,那么可以通过割去该树边和非树边分开该点,这是一个新的等价类,并且该点单独成类
			}
		}
}
void dfs3(int x){
	if(fa[x] && rcol.find(col[x]) == rcol.end())rcol[col[x]] = x;//对树边颜色映射
	for(int i = head[x]; i; i = e[i].net)
	  if(!del[i]){
		  int v = e[i].to;
		  if(v == fa[x])continue;
		  if(vis[v] != now){
			  vis[v] = now;
			  if(rcol.find(col[v]) != rcol.end()){//如果两个树边颜色相同,那么割掉这两个树边,能割掉该点,这是新的等价类
				  ull srd = rd();
				  val[rcol[col[v]]] ^= srd;
				  val[v] ^= srd;
			  }
			  dfs3(v);
		  }
	  }
}
void dfs4(int x, ull nval){//分等价类
	nval ^= val[x];
	++h[nval];//nval相同则为一个等价类
	for(int i =  head[x]; i; i = e[i].net)
		if(!del[i]){
			int v = e[i].to;
			if(v == fa[x])continue;
			if(vis[v] != now){
				vis[v] = now;
				dfs4(v, nval);
			}
		}
}
int main(){
	freopen("juice.in","r",stdin);
	freopen("juice.out","w",stdout);
	n = read(); m = read();
	s.init();
	for(int i = 1; i <= m; ++i){
		int u = read(), v = read();
		add(u, v); add(v, u); s.merge(u, v);
	}//并查集维护连通性
	for(int i = 1; i <= n; ++i)if(!dfn[i])tarjan(i, 0);//tarjan处理最小割为1的
	for(int x = 1; x <= n; ++x)
		for(int i = head[x]; i; i = e[i].net)
			if(belong[x] != belong[e[i].to])del[i] = 1;//去掉桥
	now = 0;
	for(int i = 1; i <= n; ++i)
		if(!flag[belong[i]]){
			flag[belong[i]] = 1;
			mp.clear(); h.clear(); rcol.clear(); dep[i] = 0; fa[i] = 0;
			vis[i] = ++now; dfs1(i);
			vis[i] = ++now; dfs2(i);
			vis[i] = ++now; dfs3(i);
			vis[i] = ++now; dfs4(i, 0);
			ll las = 0;
			for(auto x : h){
				ans += 3ll * x.second * (x.second - 1) / 2;
				ans += 2ll * las * x.second; 
				las += x.second;
			}
		}
	printf("%lld\n",ans);
	return 0;
}

C. 卷王

关于树的直径的奇妙性质,

考场\(Possible\) - >\(possible\) \(41 - > 1\)我是**

大力分讨构造菊花,具体不想说了

code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<random>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
mt19937 rd((ull)(new char) * (ull)(new char));

const int maxn = 1000005;
int n, p[maxn], cnt;
bool vis[maxn];

void two(int u, int v){
	if(n == 2){
		printf("Possible\n");
		printf("%d %d\n",1, 2);
		return;
	}
	int tov = 0, cv = 0, tou = 0,cu = 0, tno = 0;
	for(int i = 1;i <= n; ++i){
		if(i == u || i == v)continue;
		if(p[i] == u)++cu;
		if(p[i] == v)++cv;
	}
	for(int i = 1; i <= n; ++i)if(p[i] == u && i != v){tou = i;break;}
	for(int i = 1; i <= n; ++i)if(p[i] == v && i != u){tov = i;break;}
	for(int i = 1; i <= n; ++i)if(p[i] == -1){tno = i;break;}
	if(tov == 0 && tou == 0){
		if(n > 3){printf("Impossible\n");return;}
		int root = 0;
		for(int i = 1; i <= n; ++i)if(p[i] == -1){root = i; break;}
		printf("Possible\n");
		printf("%d %d\n", root, u);
		printf("%d %d\n", root, v);
		return;
	}
	if(tov == 0 && tou != 0){printf("Impossible\n");return;}
	if(tov != 0 && tou == 0){printf("Impossible\n");return;}
	if(cv == 1 && cu == 1){
		printf("Possible\n");
		printf("%d %d\n", u, tov);
		printf("%d %d\n", v, tou);
		if(tno){
			printf("%d %d\n", tno, tov);
			printf("%d %d\n", tno, tou);
			for(int i = 1; i <= n; ++i)if(p[i] == -1 && i != tno)printf("%d %d\n",i, tno);
		}else printf("%d %d\n",tou, tov);
		return;
	}
	if(cv == 1 && cu > 1){printf("Impossible\n");return;}
	if(cv > 1 && cu == 1){printf("Impossible\n");return;}
	printf("Possible\n");
	printf("%d %d\n", u, tov);
	printf("%d %d\n", v, tou);
	int tu = 0, tv = 0;
	for(int i = 1; i <= n; ++i)if(p[i] == u && i != v && i != tou){tu = i; break;}
	for(int i = 1; i <= n; ++i)if(p[i] == v && i != u && i != tov){tv = i; break;}
	printf("%d %d\n", tv, tov);
	printf("%d %d\n", tu, tou);
	if(tno){
		printf("%d %d\n", tno, tv);
		printf("%d %d\n", tno, tu);
		for(int i = 1; i <= n; ++i)if(p[i] == -1 && i != tno)printf("%d %d\n",i, tno);
	}else printf("%d %d\n",tu, tv);
	for(int i = 1; i <= n; ++i)if(p[i] == u && i != v && i != tou && i != tu)printf("%d %d\n",i, tu);
	for(int i = 1; i <= n; ++i)if(p[i] == v && i != u && i != tov && i != tv)printf("%d %d\n",i, tv);
}
vector<int>pu, p1;
void onlyone(){
	int u = 0;
	for(int i = 1; i <= n; ++i)if(vis[i]){u = i;break;}
	for(int i = 1; i <= n; ++i)if(p[i] == u)pu.push_back(i);else if(i != u)p1.push_back(i);
	if(pu.size() < 3 || p[u] != -1 || p1.size() == 0){printf("Impossible\n");return;}
	printf("Possible\n");
	int su = pu.size();
	for(int i = 1; i < su; ++i)printf("%d %d\n",pu[0], pu[i]);
	printf("%d %d\n",pu[0],p1[0]);
	int s1 = p1.size();
	if(s1 > 1){
		printf("%d %d\n",u, p1[1]);
		printf("%d %d\n",p1[0], p1[1]);
		for(int i = 2; i < s1; ++i)printf("%d %d\n",p1[i],p1[0]);
	}else printf("%d %d\n",u, p1[0]);
}
void work(){
	if(cnt == 1){
		if(n == 1 && p[1] == 1)printf("Possible\n");
		else if(n == 1 && p[1] != 1)printf("Impossible\n");
		else onlyone();
		return;
	}
	for(int i = 1; i <= n; ++i)if(p[i] == i || p[i] > n){printf("Impossible\n");return;}
	if(cnt >= 3){printf("Impossible\n");return;}
	if(cnt == 0){
		if(n <= 3)printf("Impossible\n");
		else{printf("Possible\n"); for(int i = 2; i <= n; ++i)printf("%d %d\n", 1, i);}
		return;
	}
	if(cnt == 2){
		int u = 0; for(int i = 1; i <= n; ++i)if(vis[i]){u = i; break;}
		int v = p[u];
		if(v == -1){printf("Impossible\n");return;}
		if(p[v] == -1){printf("Impossible\n");return;}
		else two(u, v);
	}
}
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i)scanf("%d",&p[i]);
	for(int i = 1; i <= n; ++i)
		if(p[i] > 0){
			if(!vis[p[i]])++cnt;
			vis[p[i]] = 1;
		}
	work();
	return 0;
}

标签:层省,int,long,maxn,ull,printf,include
来源: https://www.cnblogs.com/Chencgy/p/16581410.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有