*题解:CF1904F Beautiful Tree
解析
阅读完题面不难联想到差分约束,让值小的点向值大的点连边,问题在于此题涉及到单点向多点连边以及多点向单点连边。
考虑倍增优化建图,预处理出编号 \(f_{i,j}\) 表示从点 \(i\) 到 \(i\) 的 \(2^j\) 级祖先(不含)的所有点,并令 \(f_{i,j}\) 向 \(f_{i,j - 1}\) 与 \(f_{fa_{i,j - 1},j - 1}\) 连边,这样就可以将约束关系发散下去,便于处理单点向多点连边。同理,要想处理多点向单点连边,就需要反着来建图,令 \(g_{i,j - 1}\) 与 \(g_{fa_{i,j - 1},j - 1}\) 向 \(g_{i,j}\) 连边,以将约束关系汇集起来。
回到此题,只需将从 \(a\) 到 \(b\) 的路径根据 \(c\) 和 LCA 来分割,分段处理连边即可。
时间复杂度 \(O((n + m)\log n)\)。
代码
#include<bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int> pii;
const int N = 2e5 + 5,M = 20;
vector<int> t[N];
int fa[N][M],num1[N][M],num2[N][M],dep[N],ind[N * M * 2];
int res[N];
int cnt;
int head[N * M * 2],to[N * M * 6],nxt[N * M * 6];
int ecnt;
void add(int a,int b){
ecnt++;
nxt[ecnt] = head[a];
to[ecnt] = b;
head[a] = ecnt;
}
void dfs(int x,int f){
fa[x][0] = f;
dep[x] = dep[f] + 1;
num1[x][0] = ++cnt;
add(num1[x][0],x);
ind[x]++;
num2[x][0] = ++cnt;
add(x,num2[x][0]);
ind[num2[x][0]]++;
for(int i=1;i<M;i++){
fa[x][i] = fa[fa[x][i - 1]][i - 1];
if(dep[x] - (1 << i) + 1 >= 1){
num1[x][i] = ++cnt;
num2[x][i] = ++cnt;
add(num1[x][i],num1[x][i - 1]);
ind[num1[x][i - 1]]++;
add(num2[x][i - 1],num2[x][i]);
ind[num2[x][i]]++;
}
if(dep[x] - (1 << i) + 1 >= 1 && num1[fa[x][i - 1]][i - 1] != 0){
add(num1[x][i],num1[fa[x][i - 1]][i - 1]);
ind[num1[fa[x][i - 1]][i - 1]]++;
add(num2[fa[x][i - 1]][i - 1],num2[x][i]);
ind[num2[x][i]]++;
}
}
for(int nx : t[x])if(nx != f){
dfs(nx,x);
}
}
int get(int a,int b){
if(dep[a] > dep[b]) swap(a,b);
for(int i=M - 2;i>=0;i--){
if(dep[fa[b][i]] >= dep[a]){
b = fa[b][i];
}
}
if(a == b) return a;
for(int i=M - 2;i>=0;i--){
if(fa[a][i] != fa[b][i]){
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
}
void build(int a,int b,int c,int t){
for(int i=M - 2;i>=0;i--){
if(dep[fa[a][i]] >= dep[b]){
if(t == 1){
add(c,num1[a][i]);
ind[num1[a][i]]++;
}else{
add(num2[a][i],c);
ind[c]++;
}
a = fa[a][i];
}
}
}
int read(){
char c = getchar();
int a = 1,x = 0;
while(c > '9' || c < '0'){
c = getchar();
}
while(c >= '0' && c <= '9'){
x = x * 10 + c - '0';
c = getchar();
}
return a * x;
}
int main(){
// ios::sync_with_stdio(false);
// cin.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out1.txt","w",stdout);
int n = read(),m = read();
cnt = n;
for(int i=1;i<n;i++){
int u = read(),v = read();
t[u].push_back(v);
t[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=m;i++){
int t = read(),a = read(),b = read(),c = read();
int lca = get(a,b);
if(get(b,c) == c){
swap(a,b);
}
build(a,c,c,t);
if(c != lca){
build(fa[c][0],lca,c,t);
if(t == 1){
add(c,lca);
ind[lca]++;
}else{
add(lca,c);
ind[c]++;
}
}
build(b,lca,c,t);
}
queue<int> q;
for(int i=1;i<=cnt;i++){
if(!ind[i]){
q.push(i);
}
}
int now = 1;
while(!q.empty()){
int u = q.front();
q.pop();
cnt--;
if(u <= n){
res[u] = now;
now++;
}
for(int i = head[u];i;i = nxt[i]){
int v = to[i];
ind[v]--;
if(!ind[v]){
q.push(v);
}
}
}
if(cnt){
cout<<-1;
}else{
for(int i=1;i<=n;i++){
cout<<res[i]<<" ";
}
}
return 0;
}

浙公网安备 33010602011771号