Codeforces 1322 F : Assigning Fares
显然可以将条件拆成相邻边之间的方向要相同/不同。考虑二分答案 \(K\) 。
我们硬点当前节点 \(\text{x}\) 到父亲 \(\text{fa}\) 的边的方向是 \(\text{x}\to \text{fa}\)。设 \(f[x]\) 为最小的合法的填在 \(x\) 上的数,当然,如果边反向的话最大的合法的数即为 \(k+1-f[x]\) 。
现在考虑每一组互相关联的边,两个方向上的 \(f\) 的最大值分别是 \(A_1,A_2\) 。和父亲连的连通块已经确定了哪个是 \(L\) 限制,哪个是 \(R\) 限制。
最后我们需要将 \(A_1,A_2\) 一个去更新 \(L\),一个去更新 \(R\),最后要 \(L + R < K\)。
我们考虑还未确定放哪边的数,可以发现的是我们将 \(A_1,A_2\) 较大的放到一组,较小的放到一组一定是最优秀的。
之后只需要枚举一下方向就行了。
复杂度 \(O(n\log n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+5;
typedef pair<int,int> pi;
vector<int> g[N],id[N];
int n,m;
struct UST{
vector<int> fa,c;
inline void init(int n){
fa.resize(n+1);
c.resize(n+1);
for(int i=0;i<=n;i++)fa[i] = i;
}
inline int find(int x){
if(fa[x]==x)return x;
else{
find(fa[x]); c[x] ^= c[fa[x]]; fa[x] = fa[fa[x]];
return fa[x];
}
}
inline void mrg(int x,int y){
find(x),find(y);
if(fa[x]^fa[y]){
c[fa[x]]=1^c[x]^c[y];fa[fa[x]]=fa[y];
}else if(c[x]==c[y]){puts("-1");exit(0);/*no solution.*/}
}
}us[N];
int p[N];//to calc merge x , fa[x], fa[fa[x]]
int p2[N];//to calc ifedge is occipied
int dep[N],anc[N][20];
inline void adde(int u,int v){g[u].push_back(v);id[u].push_back(-1);}
inline void dfs(int x,int pre){
anc[x][0]=pre;dep[x] = dep[pre]+1;
for(int i=1;i<=19;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
us[x].init(g[x].size());
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];if(v==pre)continue;
dfs(v,x);
}
}
vector<pi> opts[N];
inline void perform(int x,int y){
if(x==y)return;
if(dep[x]<dep[y])swap(x,y);
int _x=x;
p2[x]++,p2[y]++;
for(int i=19;~i;i--)if(dep[anc[x][i]]>=dep[y])x=anc[x][i];
if(x!=y){
p[_x]++,p[y]++;
for(int i=19;~i;i--){
if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
}p[x]--,p[y]--;
opts[anc[x][0]].push_back(pi(x,y));
p2[anc[x][0]]-=2;
}else{
x=_x;p[x]++;for(int i=19;~i;i--)if(dep[anc[x][i]]>dep[y])x=anc[x][i];p[x]--;
p2[y]-=2;
}
}
int K,f[N],temp_id[N];
bool FLAG;
vector<int> h[N][2];
inline void pref(int x,int pre){
for(int j=0;j<2;j++)h[x][j].resize(g[x].size());
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];if(v==pre)continue;
pref(v,x);p[x]+=p[v];p2[x]+=p2[v];
}
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];
if(v==pre&&p2[x])id[x][i]=i;
else if(p2[v])id[x][i]=i;
}
for(size_t i=0;i<g[x].size();i++){int v=g[x][i];temp_id[v]=id[x][i];}
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];if(v!=pre&&p[v]){
us[x].mrg(temp_id[v],temp_id[pre]);
}
}
for(size_t i=0;i<opts[x].size();i++){
int a=opts[x][i].first,b=opts[x][i].second;
us[x].mrg(temp_id[a],temp_id[b]);
}
for(size_t i=0;i<g[x].size();i++){
if(id[x][i]!=-1){
us[x].find(id[x][i]);
}
}
}/* to make the union set */
int dir[N];
inline void Dp(int x,int pre){
f[x]=1;
for(int i=0;i<(int)g[x].size();i++)h[x][0][i]=h[x][1][i]=0;
int qwq[2]={0,0};
int idd=-1,cidd=0;
for(size_t i=0;i<g[x].size();i++){
if(g[x][i]==pre){
if(id[x][i]!=-1)idd=us[x].fa[id[x][i]],cidd=us[x].c[id[x][i]];
}
}
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];if(v==pre)continue;
Dp(v,x);
if(id[x][i]!=-1){
if(us[x].fa[id[x][i]]==idd){
dir[v]=(us[x].c[id[x][i]]==cidd);
if(us[x].c[id[x][i]]!=cidd)qwq[0]=max(qwq[0],f[v]);
else qwq[1]=max(qwq[1],f[v]);
}
else{
h[x][us[x].c[id[x][i]]][us[x].fa[id[x][i]]]=max(h[x][us[x].c[id[x][i]]][us[x].fa[id[x][i]]],f[v]);
}
}
}
int qaq[2]={0,0};
for(size_t i=0;i<g[x].size();i++){
int a=min(h[x][0][i],h[x][1][i]), b=max(h[x][0][i],h[x][1][i]);
qaq[0]=max(qaq[0],a);
qaq[1]=max(qaq[1],b);
}
int type=0;
if(max(qaq[0],qwq[0])+max(qwq[1],qaq[1])<K){
f[x]=max(qaq[0],qwq[0])+1;
}
else{
type=1;
if(max(qaq[1],qwq[0])+max(qwq[1],qaq[0])<K)f[x]=max(qaq[1],qwq[0])+1;
else FLAG=0,f[x]=1;
}
for(size_t i=0;i<g[x].size();i++){
int v=g[x][i];if(v==pre)continue;
if(id[x][i]!=-1){
if(us[x].fa[id[x][i]]==idd)continue;
int idx = us[x].fa[id[x][i]], c = us[x].c[id[x][i]];
int cc = c^(h[x][0][idx]>h[x][1][idx])^type;
dir[v]=cc;
}
}
}
inline bool check(int k){
K=k,FLAG=1;
Dp(1,0);
return FLAG;
}
bool t[N];
int ans[N];
inline void getans(int x,int pre){
ans[x]=t[x]?K+1-f[x]:f[x];
for(size_t i=0;i<g[x].size();i++){
if(g[x][i]==pre)continue;
t[g[x][i]]=t[x]^dir[g[x][i]];
getans(g[x][i],x);
}
}
int main()
{
cin >> n >> m;
for(int i=1;i<n;i++){
int u,v;scanf("%d%d",&u,&v);
adde(u,v),adde(v,u);
}
dfs(1,0);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
perform(u,v);
}
pref(1,0);
int l=1,r=n;
while(l<r){
int mid = (l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout << l << endl;
check(l);
getans(1,0);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
puts("");return 0;
}