点这里看题目
我考场上做这道题的时候真的可以说是脑子里一片浆糊。看来还是太菜了。
能把这题搞懂(?)还是归功于学长的博客。
先考虑树的情形。但是我是真没想到能推广到图上。不过还是应该相信出题人吧,毕竟有树的部分分。 不妨假设 1 1 1为根,方便起见字符串下标从 2 ∼ n 2\sim n 2∼n编号。对于每个点 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 lca→j这条链上的点 p p p, c i , p c_{i,p} ci,p随深度增加应该是不降的,并且对于 p ∈ { l c a → j } p\in \{lca\to j\} p∈{lca→j},有 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,fap≤ci,p≤ci,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 lca→j的链记录当突变点为 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 i→lca的链记录当突变点为 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";
}
}