题解:P3549 [POI2013] MUL-Multidrink
机房大佬说这题思路上没有黑题的压迫感。
不妨拎起
于是考虑对一棵子树的遍历,同理进入儿子子树就应该遍历完,显然树形 dp,记
转移大力分讨即可:
最后,将链上的子树方案合并起来,肯定从左到右一个个地遍历,记
输出方案按转移进行即可。复杂度
代码
依托答辩,难以评价。
#include<bits/stdc++.h>
using namespace std;
const int N = 6e5 + 5;
int n, u, v, d[N], dist[N], dn;
bool vis[N], f[N][3], g[N][2];
vector<int> to[N], son[N], ans;
inline void init(int u, int from){
for(auto v : to[u])
if(v ^ from) init(v, u), vis[u] |= vis[v];
if(u == n) vis[u] = true;
if(vis[u]) dist[++dn] = u;
}
inline void dfs(int u){
vis[u] = true;
for(auto v : to[u])
if(!vis[v]) dfs(v), son[u].push_back(v);
f[u][0] = son[u].empty();
if(!son[u].empty()){
f[u][1] = true;
int cnt = 0;
for(auto v : son[u])
if(!f[v][0]){
if(!f[v][1]) f[u][1] = false;
else if(++cnt > 1) f[u][1] = false;
}
}
if(son[u].size() >= 2){
f[u][2] = true;
int cnt = 0;
for(auto v : son[u])
if(!f[v][0]){
if(!f[v][1]) f[u][2] = false;
else if(++cnt > 2) f[u][2] = false;
}
}
}
inline void print(int u, int id){
//0:叶
//1:u进v出
//2: v进u出
//3:v进v出
if(!id) ans.push_back(u);
if(id == 1){
ans.push_back(u);
for(auto v : son[u]) if(!f[v][0]) print(v, 2);
for(auto v : son[u]) if(f[v][0]) print(v, 0);
}
if(id == 2){
for(auto v : son[u]) if(f[v][0]) print(v, 0);
for(auto v : son[u]) if(!f[v][0]) print(v, 1);
ans.push_back(u);
}
if(id == 3){
int fir = 0, sec = 0;
for(auto v : son[u])
if(!f[v][0]){
if(!fir) fir = v;
else sec = v;
}
if(!fir){
for(auto v : son[u])
if(f[v][0]){
print(v, 0);
if(!fir) ans.push_back(u), fir = 1;
}
}
else{
for(auto v : son[u]) if(f[v][0]) print(v, 0);
bool fl = false;
for(auto v : son[u])
if(!f[v][0]){
if(!fl) print(v, 1), ans.push_back(u), fl = true;
else print(v, 2);
}
}
}
}
inline void print2(int i, int id){
if(i == 1){
if(!id) print(dist[i], 0);
else print(dist[i], 1);
return ;
}
if(!id){
if(g[i - 1][0] && f[dist[i]][0]) print2(i - 1, 0), print(dist[i], 0);
else if(g[i - 1][0] && f[dist[i]][1]) print2(i - 1, 0), print(dist[i], 2);
else if(g[i - 1][1] && f[dist[i]][0]) print2(i - 1, 1), print(dist[i], 0);
}
else
if(g[i - 1][0] && f[dist[i]][1]) print2(i - 1, 0), print(dist[i], 1);
else if(g[i - 1][0] && f[dist[i]][2]) print2(i - 1, 0), print(dist[i], 3);
else if(g[i - 1][1] && f[dist[i]][1]) print2(i - 1, 1), print(dist[i], 1);
}
signed main(){
cin >> n;
for(int i = 1; i < n; ++i) scanf("%d%d", &u, &v), to[u].push_back(v), to[v].push_back(u);
init(1, 0);
reverse(dist + 1, dist + 1 + dn);
for(int i = 1; i <= dn; ++i) dfs(dist[i]);
g[1][0] = f[dist[1]][0], g[1][1] = f[dist[1]][1];
for(int i = 2; i <= dn; ++i){
g[i][0] = (g[i - 1][0] & (f[dist[i]][0] | f[dist[i]][1])) | (g[i - 1][1] & f[dist[i]][0]);
g[i][1] = (g[i - 1][0] & (f[dist[i]][1] | f[dist[i]][2])) | (g[i - 1][1] & f[dist[i]][1]);
}
if(!g[dn][0]) puts("BRAK");
else{
print2(dn, 0);
for(auto i : ans) printf("%d\n", i);
}
return 0;
}