CF1322F Assigning Fares
首先,如果存在一种分配方案,那么显然答案 \(k\) 在 \([1,n]\) 中。
而显然 \(k\) 具有单调性,所以可以二分。
接下来考虑判定对于一个给定的答案 \(k\) 是否可行并且给出一组构造。
考虑树上的每条边 \((u,p_u)\) ,如果它没有被任何路径覆盖,则可以不考虑这条边。
否则,由于它被某几条路径覆盖,则它的两个端点必定为以下两种状态之一(称为 \(d_i\)):
-
\(c_u<c_{p_u}\),称这种边为 \(A\) 类边。
-
\(c_u>c_{p_u}\),称这种边为 \(B\) 类边。
而一条路径的作用就是限制若干个 \(d_i\) 的取值相同或相反。
这里可以拿个权值并查集来做。
因此所有被覆盖的边 \((u,p_u)\) 就被划分成了若干个联通块,且一整个联通快只有两种取 \(d_i\) 的方案。
然后考虑树形 DP。令 \(dp_u\) 表示边 \((u,p_u)\) 为 \(A\) 类边(若没有被任何边覆盖可以直接忽略)时 \(c_v\) 的最小值。且根据对称性,若边 \((u,p_u)\) 为 \(B\) 类边,则最大值为 \(k+1-c_u\)。
然后考虑怎么求出 \(dp\)。
若 \(u\) 为叶节点则有 \(dp_u=1\)。
而对于其他节点,则考虑对于每个子树找出对 \(dp_u\) 限制的区间或集合,最后取交集的最小值。
而 \(u\) 的子树 \(v\) 分为三种情况:
- \((v,u)\) 没有被任何路径覆盖:
同理可以直接忽略。
- \((v,u)\) 和 \((u,p_u)\) 在同一个联通快中:
由于已经假设 \((u,p_u)\) 为 \(A\) 型边,于是同样可以知道 \((v,u)\) 的类型,所以:
-
若 \((v,u)\) 为 \(A\) 型边,则 \(c_u> c_v\),限制区间为 \([c_v+1,k]\)。
-
若 \((v,u)\) 为 \(B\) 型边,则 \(c_u<c_v\),限制区间为 \([1,c_v-1]\)。
- \((v,u)\) 和 \((u,p_u)\) 不在同一个联通快中:
假设 \((v,u)\) 所在的联通块为 \(C\),那么此时 \(C\) 中的所有边都在 \(u\) 的子树内,此时对整个 \(C\) 一起处理。记联通块 \(C\) 中和 \(u\) 有关联的边有 \((v_1,u),(v_2,u)\cdots (v_k,u)\)。和上面同理,因为可以钦定这些边的类型,再取交求出 \(c_u\) 的限制区间 \([l,r]\)。再由对称性另一种钦定对 \(c_u\) 的限制区间就是 \([k+1-r,k+1-l]\)。因此整个 \(C\) 对 \(c_u\) 的限制集合就是 \([l,r]\cup [k+1-r,k+1-l]\)。
最后就是对所有限制取交集然后取最小元素。
如果没有第三种情况就是区间求交,直接取左端点的最大值和右端点的最喜哦值即可。但是第三种情况有可能不是一个区间。
考虑这个集合的性质,如果 \([l,r]\cup [k+1-r,k+1-l]\) 不是一个区间,则它一定是关于 \(\frac{k+1}{2}\) 对称的两个区间。
因此这样一个集合都可以分为左边和右边两个区间,我们只需要对左边的区间求交,然后再对称到右边的区间,即可得到最终交,记为 \([l',r']\cup [k+1-r',k+1-l']\)。
然后考虑计算 \(dp_u\) 。
设其他正常交出来的区间为 \([l,r]\),如果 \(\max(l,l')\) 不在 \((r;,k+1-r')\) 中,则 \(dp_u=\max(l,l')\)。
否则考虑 \(k+1-r'\) 是否超过 \(\max(r,k+1-l')\) 如果超过显然无解。否则答案就是 \(k+1-r'\)。
最后因为可以通过 \(dp_u\) 求出它各个子树每被路径覆盖的边是什么类型。所以只需要对每条边记录在最终方案时它是否和上一条边类型相同即可,直接输出即可。
时间复杂度 \(\mathcal O(n\log n)\)。
#include<bits/stdc++.h>
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
int n,m;
vector<int>e[555555];
inline void ns()
{
cout<<"-1"<<endl;
exit(0);
}
struct dsu
{
int fa[555555];
bool v[555555];
inline void clear()
{
R(i,1,n) fa[i]=i,v[i]=0;
}
int fnd(int x)
{
if(x==fa[x]) return x;
int f=fa[x];
fa[x]=fnd(fa[x]);
v[x]^=v[f];
return fa[x];
}
inline void mrg(int x,int y,int k)
{
//printf("mrg: x:%d y:%d k:%d\n",x,y,k);
int fx=fnd(x),fy=fnd(y),t=v[x]^v[y]^k;
if(fx==fy)
{
if(t) ns();
}
else fa[fx]=fy,v[fx]=t;
}
}dsu;
struct tree
{
int hson[555555],htop[555555],dfn[555555],pos[555555],tim;
int siz[555555],dep[555555],fa[555555];
int v[555555],vv[555555];
void dfs1(int u,int f)
{
siz[u]=1;
int mx=-1;
for(int v:e[u]) if(v^f)
{
fa[v]=u;dep[v]=dep[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>mx) hson[u]=v,mx=siz[v];
}
}
void dfs2(int u,int topf)
{
dfn[u]=++tim;
pos[tim]=u;
htop[u]=topf;
if(!hson[u]) return;
dfs2(hson[u],topf);
for(int v:e[u]) if(v^fa[u]&&v^hson[u]) dfs2(v,v);
}
inline int LCA(int x,int y)
{
while(htop[x]^htop[y])
{
if(dep[htop[x]]<dep[htop[y]]) swap(x,y);
x=fa[htop[x]];
}
return dep[x]<dep[y]?x:y;
}
int jmp(int x,int y)
{
while(1)
{
if(dep[htop[x]]<=dep[y]) return pos[dfn[y]+1];
if(dep[htop[x]]==dep[y]+1) return htop[x];
x=fa[htop[x]];
}
assert(0);
}
void ins(int x,int y)
{
int l_a=LCA(x,y);
++v[x],++v[y],v[l_a]-=2;
if(x^l_a) ++vv[x],--vv[x=jmp(x,l_a)];
if(y^l_a) ++vv[y],--vv[y=jmp(y,l_a)];
if((x^l_a)&&(y^l_a)) dsu.mrg(x,y,1);
}
void mian()
{
L(i,1,n)
{
int x=pos[i];
v[fa[x]]+=v[x],vv[fa[x]]+=vv[x];
if(vv[x]) dsu.mrg(x,fa[x],0);
}
}
}tr;
int vis[555555],tim;
int dp[555555];
int vl[555555],vr[555555];
int rev[555555],s[555555];
inline int check(int k)
{
deque<int>q;
L(i,1,n)
{
int u=tr.pos[i],f=tr.fa[u];
int l=0,r=0;
++tim;
for(int v:e[u]) if(v^f&&tr.v[v])
{
int fv=dsu.fa[v];
if(vis[fv]!=tim) vis[fv]=tim,vl[fv]=vr[fv]=0,q.emplace_back(fv);
if(!dsu.v[v]) vl[fv]=max(vl[fv],dp[v]);
else vr[fv]=max(vr[fv],dp[v]);
}
int fv=dsu.fa[u];
if(vis[fv]==tim)
{
l=vl[fv],r=vr[fv];
if(dsu.v[u]) swap(l,r);
}
int mn=0,mx=0;
while(q.size())
{
int x=q.front();
q.pop_front();
if(x!=fv)
{
if(vl[x]>vr[x]) swap(vl[x],vr[x]);
mn=max(mn,vl[x]),mx=max(mx,vr[x]);
}
}
if(max(mn,min(l,r))+max(mx,max(l,r))>=k) return 0;
dp[u]=(max(mn,l)+max(mx,r)>=k?max(mx,l):max(mn,l))+1;
}
return 1;
}
void solve(int k)
{
deque<int>q;
R(i,1,n)
{
int u=tr.pos[i],f=tr.fa[u];
++tim;
for(int v:e[u]) if(v^f&&tr.v[v])
{
int fv=dsu.fa[v];
if(vis[fv]!=tim) vis[fv]=tim,vl[fv]=vr[fv]=0,q.emplace_back(fv);
if(!dsu.v[v]) vl[fv]=max(vl[fv],dp[v]);
else vr[fv]=max(vr[fv],dp[v]);
}
while(q.size())
{
int x=q.front();
q.pop_front();
s[x]=rev[u];
if(x!=dsu.fa[u]) s[x]^=((vl[x]>=dp[u])||(vr[x]+dp[u]>k));
else s[x]^=dsu.v[u];
}
for(int v:e[u]) if(v^f&&tr.v[v]) rev[v]=s[dsu.fa[v]]^dsu.v[v];
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n>>m;
R(i,1,n-1)
{
int x,y;
cin>>x>>y;
e[x].emplace_back(y),e[y].emplace_back(x);
}
dsu.clear();tr.dfs1(1,0);tr.dfs2(1,1);
R(i,1,m)
{
int x,y;
cin>>x>>y;
tr.ins(x,y);
}
tr.mian();
R(i,1,n) dsu.fnd(i);
int l=1,r=n,ans=0;
while(r-l>5)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
R(i,l,r) if(check(i))
{
ans=i;
break;
}
cout<<ans<<endl;
check(ans);
solve(ans);
R(i,1,n) cout<<((!rev[i])?dp[i]:ans+1-dp[i])<<" ";
cout<<endl;
}

浙公网安备 33010602011771号