题意:给定一棵n个结点的树,问:对于每个结点,能否通过删除一条边并添加一条边使得仍是树,并且删除该结点后得到的各个连通分量结点数 <= n/2?
题解:树形dp,两遍dfs,第一遍dfs求得以各个结点为根的子树的结点数,以及各个结点下面切掉某条边后最多可切出多少个结点;
第二遍dfs求得每个结点上面切掉某条边后最多可切出多少个结点。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 4e5+1; 5 vector<int> ve[N]; 6 bool vis[N]; 7 int num[N], maxson[N], down[N], up[N]; 8 int n; 9 void dfs(int x){ 10 vis[x] = true; 11 num[x] = 1; 12 maxson[x] = 0; 13 down[x] = 0; 14 for(int i = 0; i < ve[x].size(); i++){ 15 int y = ve[x][i]; 16 if(vis[y]) continue ; 17 dfs(y); 18 num[x] += num[y]; 19 maxson[x] = max(maxson[x], num[y]); 20 down[x] = max(down[x], num[y] <= n/2? num[y]: down[y]); 21 } 22 } 23 void debug(vector<int>& v){ 24 puts("***"); 25 cout << v.size() << endl; 26 for(int i = 0; i < v.size(); i++) 27 cout << v[i] << ‘ ‘; 28 puts(""); 29 puts("****"); 30 } 31 void dfs2(int f, int x){ 32 vis[x] = true; 33 int tot = ve[x].size(); 34 vector<int> tmp(tot), pre(tot), hou(tot); 35 for(int i = 0; i < tot; i++){ 36 int y = ve[x][i]; 37 if(vis[y]) tmp[i] = 0; 38 else 39 tmp[i] = num[y] <= n/2? num[y]:down[y]; 40 } 41 for(int i = 0; i < tot; i++){ 42 pre[i] = tmp[i]; 43 if(i) pre[i] = max(pre[i], pre[i-1]); 44 } 45 for(int i = tot-1; i >= 0; i--){ 46 hou[i] = tmp[i]; 47 if(i != tot-1) hou[i] = max(hou[i], hou[i+1]); 48 } 49 for(int i = 0; i < tot; i++){ 50 int y = ve[x][i]; 51 if(vis[y]) continue ; 52 if(n-num[y] <= n/2) 53 up[y] = n-num[y]; 54 else { 55 up[y] = up[x]; 56 if(i+1 < tot) 57 up[y] = max(up[y], hou[i+1]); 58 if(i-1 >= 0) 59 up[y] = max(up[y], pre[i-1]); 60 } 61 dfs2(x, y); 62 } 63 } 64 65 int main(){ 66 int u, v; scanf("%d", &n); 67 for(int i = 1; i < n; i++){ 68 scanf("%d%d", &u, &v); 69 ve[u].push_back(v), ve[v].push_back(u); 70 } 71 dfs(1); 72 memset(vis, 0, sizeof(vis)); 73 dfs2(0, 1); 74 bool tag; 75 // for(int i = 1; i <= n; i++) 76 // cout << maxson[i] << ‘ ‘ << num[i] << ‘ ‘ << down[i] << ‘ ‘ << up[i] << endl; 77 for(int i = 1; i <= n; i++){ 78 if(maxson[i] <= n/2&&n-num[i] <= n/2)//不用切 79 tag = true; 80 else if(n-num[i] > n/2)//要切上面 81 tag = n-num[i]-up[i] <= n/2; 82 else//要切下面 83 tag = maxson[i]-down[i] <= n/2; 84 putchar(tag+‘0‘); 85 putchar(i == n? ‘\n‘:‘ ‘); 86 } 87 return 0; 88 }
时间: 2024-10-31 02:38:49