CF神奇構造題
題目大意
給出一顆 \(N\) 個節點樹,每條邊有邊權,邊權為 \(0\) 到 \(N-2\) 的整數,且不重復,使得任意兩點的簡單路徑的MEX的最大值最小.(MEX指第一個沒有出現過的非負整數)
分析
對於MEX最重要自然是 \(0\),而且因為是樹,所以必然可以做到將 \(0\) 和 \(1\) 放入同一條樹鏈中,那么就要考慮 \(2\) 的位置了,不可以讓他出現在這條樹鏈中,理解一下就是必須有一個點的度至少為 \(3\),即這個圖不是一條鏈,那么就有一種非常容易的方法,將 \(0,1,2\) 放在三個度為 \(1\) 的點的邊上,這樣就不可能出現 \(0,1,2\) 同時出現在一條鏈上,其他也就可以亂放了,如果是一條鏈無論怎么放MEX都可以達到 \(N-1\),所以可以直接亂放.
代碼
#include<bits/stdc++.h>
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
const int MAXN=114514;
int N,M;
int T;
int out[MAXN];//記錄度
int p[MAXN];//比較懶,不想存圖,所以就只記錄一下每個點最后一條出邊,反正最后有影響的之后度為1的點,所以沒關系
int answer[MAXN];//記錄答案
void work()
{
scanf("%d",&N);
int f,t;
REP(i,1,N-1)
{
scanf("%d%d",&f,&t);
out[f]++;
out[t]++;
p[f]=p[t]=i;
}
if(N==2)//注意特判2
{
printf("%d",0);
return;
}
int cnt=0;
REP(i,1,N)
{
if(out[i]==1)//在前三個度為1的點的出邊賦值上0,1,2,為了方便處理這里就用了1,2,3
{
answer[p[i]]=++cnt;
if(cnt==3)
{
break;
}
}
}
REP(i,1,N-1)//輸出
{
if(answer[i])//如果有答案就輸出答案
{
printf("%d\n",answer[i]-1);
}
else//沒有反正可以亂輸出
{
++cnt;
printf("%d\n",cnt-1);
}
}
}
int main()
{
work();
return 0;
}
