【学习笔记】NOI 模拟赛 t2 momo

点这里看题目

我考场上做这道题的时候真的可以说是脑子里一片浆糊。看来还是太菜了。

能把这题搞懂(?)还是归功于学长的博客。

先考虑树的情形。但是我是真没想到能推广到图上。不过还是应该相信出题人吧,毕竟有树的部分分。 不妨假设 1 1 1为根,方便起见字符串下标从 2 ∼ n 2\sim n 2n编号。对于每个点 i i i,如果 x x x(除 1 1 1外)在 1 1 1 i i i的链上,那么将第 x x x位设为 M M M,其余全部设为 O O O。这样对于任意两个点都是满足要求的。

对于一般图的情形,考虑以 1 1 1为根建立 B F S BFS BFS树。说实话,这一步非常困难。 B F S BFS BFS树上,一个点的深度就是它到 1 1 1号节点的距离。定义 c i , j c_{i,j} ci,j表示 i , j i,j i,j B F S BFS BFS树上的距离减去在图上的距离,如果 i , j i,j i,j满足祖先关系那么显然 c i , j = 0 c_{i,j}=0 ci,j=0。否则考虑一对没有祖孙关系的 i , j i,j i,j,有 c i , l c a = c j , l c a = 0 c_{i,lca}=c_{j,lca}=0 ci,lca=cj,lca=0,并且 c i , j = c j , i c_{i,j}=c_{j,i} ci,j=cj,i

注意到对于 l c a → j lca\to j lcaj这条链上的点 p p p c i , p c_{i,p} ci,p随深度增加应该是不降的,并且对于 p ∈ { l c a → j } p\in \{lca\to j\} p{lcaj},有 c i , f a p ≤ c i , p ≤ c i , f a p + 2 c_{i,fa_p}\le c_{i,p}\le c_{i,fa_p}+2 ci,fapci,pci,fap+2。为了不影响到其他点的合法性,我们假定 { c i , j } \{c_{i,j}\} {ci,j}是静止不变的。记 k = c i , j > 0 k=c_{i,j}>0 k=ci,j>0,考虑将 1 1 1 k k k的数按奇偶性分类,对于 l c a → j lca\to j lcaj的链记录当突变点为 1 , 3 , 5 , . . . 1,3,5,... 1,3,5,...时所到达的点 x x x,然后将 i i i的第 x x x位设置为通配符。同理对于 i → l c a i\to lca ilca的链记录当突变点为 2 , 4 , 6 , . . . 2,4,6,... 2,4,6,...时所到达的点 x x x,然后将 j j j的第 x x x位设置为通配符。这样我们发现恰好修改了 k k k个地方的字符,并且任意两个数对之间的构造是不矛盾的,这只需要对 D F N DFN DFN序进行比较就能得出。

瓶颈在于求最短路。复杂度 O ( n 3 ) O(n^3) O(n3)

挺妙的。尽量意会一下吧。

#include
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int n,m,a[505][505],c[505][505],dep[505],fa[505],dfn[505],num;
queue<int>Q;
vector<int>G[505];
string s[505];
void dfs(int u,int topf){
	dfn[u]=++num;
	for(auto v:G[u]){
		if(v!=topf){
			dfs(v,u);
		}
	}
}
void dfs(int u,int v,int pre,int lca){
	c[u][v]=dep[u]+dep[v]-2*dep[lca]-a[u][v];
	assert(c[u][v]>=c[u][pre]);
	assert(c[u][v]<=c[u][pre]+2);
	if(dfn[v]>dfn[u]){
		if((c[u][v]+1)/2!=(c[u][pre]+1)/2){
			s[u][v]='_';
		}
	}
	else{
		if(c[u][v]/2!=c[u][pre]/2){
			s[u][v]='_';
		}
	}
	for(auto k:G[v]){
		if(k!=pre){
			dfs(u,k,v,lca);
		}
	}
}
void check(){
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			int tot=0;
			for(int k=2;k<=n;k++){
				if(s[i][k]=='M'&&s[j][k]=='O'||s[i][k]=='O'&&s[j][k]=='M'){
					tot++;
				}
			}
		}
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
	cin>>n>>m,memset(a,0x3f,sizeof a);
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		a[u][v]=a[v][u]=1;
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
			}
		}
	}
	memset(dep,-1,sizeof dep);
	Q.push(1),dep[1]=0;
	for(int i=1;i<=n;i++)s[i].resize(n+1);
	for(int i=2;i<=n;i++)s[1][i]='O';
	while(Q.size()){
		int u=Q.front();Q.pop();
		for(int v=1;v<=n;v++){
			if(a[u][v]==1&&dep[v]==-1){
				dep[v]=dep[u]+1;
				G[u].pb(v),fa[v]=u;
				s[v]=s[u],s[v][v]='M';
				Q.push(v);
			}
		}
	}
	dfs(1,0);
	for(int i=1;i<=n;i++){
		for(int j=fa[i],pre=i;j;pre=j,j=fa[j]){
			for(auto k:G[j]){
				if(k!=pre){
					dfs(i,k,j,j);
				}
			}
		}
	}
	check(); 
	for(int i=1;i<=n;i++){
		for(int j=2;j<=n;j++){
			cout<<s[i][j];
		}
		cout<<"\n";
	}
}

你可能感兴趣的:(学习,笔记,深度优先)