方法一:
主要思想是从两个已经有值了的顶点向中间扩散,因为要使最后扩散完后两端最后扩散到的两个数差为1,所以可以考虑成要使扩散完后两端最后扩散到的两个数的差最小且不为0,于是可以使用贪心算法,每次取一个值最小的顶点开始扩散。如果最后扩散出的有2个相邻的顶点的值得差不为1,则为非法情况。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 typedef unsigned long long ull; 6 typedef pair<int, int> i_i; 7 typedef pair<ll, int> ll_i; 8 typedef pair<double, int> d_i; 9 typedef pair<ll, ll> ll_ll; 10 typedef pair<double, double> d_d; 11 struct edge { int v, w; }; 12 13 #define rep(i, N) for (int i = 0; i < N; i++) 14 #define pb push_back 15 16 ll MOD = 1000000007; 17 ll _MOD = 1000000009; 18 ll e10 = 1e10 + 10; 19 double EPS = 1e-10; 20 21 int main() { 22 int N; cin >> N; 23 vector<vector<int> > G(N); 24 rep(i, N - 1) { 25 int a, b; scanf("%d%d", &a, &b); 26 a--; b--; 27 G[a].pb(b); 28 G[b].pb(a); 29 } 30 vector<int> d(N, -1); 31 priority_queue<i_i, vector<i_i>, greater<i_i> > pq; 32 int K; cin >> K; 33 while (K--) { 34 int v, p; scanf("%d%d", &v, &p); 35 v--; 36 d[v] = p; 37 pq.push(i_i(p, v)); 38 } 39 while (!pq.empty()) { 40 i_i p = pq.top(); pq.pop(); 41 int u = p.second; 42 cout<<u<<" "<<d[u]<<endl; 43 for (int v,i=0;i<G[u].size();i++){ 44 v=G[u][i]; 45 if (d[v] == -1) { 46 d[v] = d[u] + 1; 47 pq.push(i_i(d[v], v)); 48 } 49 } 50 } 51 rep(u, N) 52 for (int i=0;i<G[u].size();i++){ 53 int v=G[u][i]; 54 if (abs(d[u] - d[v]) != 1) { 55 cout << "No" << endl; 56 return 0; 57 } 58 } 59 cout << "Yes" << endl; 60 rep(u, N) printf("%d\n", d[u]); 61 }
方法二:
用树形dp,dp出每个顶点可以取的数的上限和下限,如果满足奇偶性要求并且上限不大于下限则必有一组合法解。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int INF = 1e9; 5 const int N = 110000; 6 7 int n; 8 vector<int> g[N]; 9 int known[N], val[N]; 10 int K; 11 int l[N], r[N]; 12 int used[N]; 13 int known_parity[N][2]; 14 int shit; 15 16 vector<int> order; 17 int par[N]; 18 19 void dfs(int v) 20 { 21 used[v] = 1; 22 23 l[v] = -1e9; 24 r[v] = 1e9; 25 for (int i = 0; i < g[v].size(); i++) 26 { 27 int to = g[v][i]; 28 if (used[to]) 29 continue; 30 dfs(to); 31 par[to] = v; 32 if (known_parity[to][0]) 33 known_parity[v][1] = 1; 34 if (known_parity[to][1]) 35 known_parity[v][0] = 1; 36 l[v] = max(l[v], l[to] - 1); 37 r[v] = min(r[v], r[to] + 1); 38 } 39 40 if (known[v] == 1) 41 { 42 l[v] = max(l[v], val[v]); 43 r[v] = min(r[v], val[v]); 44 known_parity[v][val[v] % 2] = 1; 45 } 46 47 if (known_parity[v][0] == 1 && known_parity[v][1] == 1) 48 { 49 shit = 1; 50 } 51 52 if (l[v] > r[v]) 53 shit = 1; 54 55 order.push_back(v); 56 } 57 58 int ans[N]; 59 60 int solve_val(int v, int par) 61 { 62 if (par == 0) 63 { 64 return l[v]; 65 } 66 l[v] = max(l[v], ans[par] - 1); 67 r[v] = min(r[v], ans[par] + 1); 68 while (l[v] % 2 == ans[par] % 2) 69 ++l[v]; 70 return l[v]; 71 } 72 73 int main(){ 74 //freopen("fabro.in","r",stdin); 75 //freopen("fabro.out","w",stdout); 76 //freopen("F:/in.txt", "r", stdin); 77 //freopen("F:/output.txt", "w", stdout); 78 ios_base::sync_with_stdio(0); 79 //cin.tie(0); 80 81 cin >> n; 82 for (int i = 1; i < n; i++) 83 { 84 int a, b; 85 cin >> a >> b; 86 g[a].push_back(b); 87 g[b].push_back(a); 88 } 89 90 cin >> K; 91 for (int i = 1; i <= K; i++) 92 { 93 int a, b; 94 cin >> a >> b; 95 known[a] = 1; 96 val[a] = b; 97 } 98 99 dfs(1); 100 101 if (shit) 102 { 103 cout << "No" << endl; 104 return 0; 105 } 106 107 reverse(order.begin(), order.end()); 108 109 cout << "Yes" << endl; 110 111 for (int i = 0; i < order.size(); i++) 112 { 113 int v = order[i]; 114 if (par[v] == 0) 115 { 116 ans[v] = solve_val(v,par[v]); 117 } 118 else 119 { 120 ans[v] = solve_val(v, par[v]); 121 } 122 } 123 124 for (int i = 1; i <= n; i++) 125 { 126 cout << ans[i] << endl; 127 } 128 129 cin.get(); cin.get(); 130 return 0; 131 }
方法三:
主要思想是设u为v的子树中的一个点,任意u都满足dep[u]-dep[v]>=ans[u]-ans[v]&&dep[u]>=ans[v]-ans[u]是子树合法的充分必要条件,可以变形为dep[u]-ans[u]>=dep[v]-ans[v]&&dep[u]+ans[u]>=dep[v]-ans[v],于是可以建线段树,线段树中的每一个叶子结点的下标表示ans[v]的一个值,叶子结点的值表示dep[u]-ans[u]和dep[u]+ans[u],每一个节点的值表示[l,r]中dep[u]-ans[u]的最小值和dep[u]+ans[u]的最小值,构造的时候可以直接查询当前填上的ans[v]是否满足dep[u]-ans[u]>=dep[v]-ans[v]且dep[u]+ans[u]>=dep[v]-ans[v]。这里要用到线段树合并。
1 #include<bits/stdc++.h> 2 #define per(i,j,k) for(int i=(int)j;i>=(int)k;i--) 3 #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) 4 using namespace std; 5 const int N=110000; 6 int head[N],np[N<<1],p[N<<1],tot; 7 int key[N]; 8 int n,K; 9 int root; 10 int fa[N]; 11 int dep[N]; 12 int dx[2]={-1,1}; 13 int seg[N],cl[N*35],cr[N*35],segtot,mi[N*35][2]; 14 void copy(int x,int y){ 15 if(!y){ 16 rep(i,0,1)mi[x][i]=(1e9); 17 } 18 else{ 19 cl[x]=cl[y]; 20 cr[x]=cr[y]; 21 rep(i,0,1)mi[x][i]=mi[y][i]; 22 } 23 } 24 void insert(int &me,int l,int r,int x,int v){ 25 ++segtot; 26 copy(segtot,me); 27 me=segtot; 28 if(l==r){ 29 rep(i,0,1)mi[me][i]=v+dx[i]*x; 30 return; 31 } 32 int mid=(l+r)>>1; 33 if(x<=mid)insert(cl[me],l,mid,x,v); 34 else insert(cr[me],mid+1,r,x,v); 35 36 rep(i,0,1)mi[me][i]=min(mi[cl[me]][i],mi[cr[me]][i]); 37 } 38 int merge(int a,int b,int l,int r){ 39 if(!a||!b)return a+b; 40 int d=++segtot; 41 42 if(l==r){ 43 rep(i,0,1)mi[d][i]=min(mi[a][i],mi[b][i]); 44 return d; 45 } 46 int mid=(l+r)>>1; 47 cl[d]=merge(cl[a],cl[b],l,mid); 48 cr[d]=merge(cr[a],cr[b],mid+1,r); 49 rep(i,0,1)mi[d][i]=min(mi[cl[d]][i],mi[cr[d]][i]); 50 return d; 51 } 52 void dfs(int x){ 53 for(int u=head[x];u;u=np[u])if(p[u]^fa[x]){ 54 fa[p[u]]=x;dep[p[u]]=dep[x]+1;dfs(p[u]); 55 seg[x]=merge(seg[x],seg[p[u]],0,100000); 56 } 57 if(key[x]>=0){ 58 insert(seg[x],0,100000,key[x],dep[x]); 59 } 60 } 61 int ask(int k,int me,int l,int r,int x,int y){ 62 if((x>y)||(!me))return 1000000000; 63 if(x<=l&&r<=y)return mi[me][k]; 64 int ret=1000000000; 65 int mid=(l+r)>>1; 66 if(x<=mid){ 67 int D=ask(k,cl[me],l,mid,x,y); 68 if(D<ret)ret=D; 69 } 70 if(y>mid){ 71 int D=ask(k,cr[me],mid+1,r,x,y); 72 if(D<ret)ret=D; 73 } 74 return ret; 75 } 76 void work(int x,int fav){ 77 //printf("%d %d\n",x,fav); 78 if(key[x]>=0){ 79 fav=key[x]; 80 for(int u=head[x];u;u=np[u])if(p[u]^fa[x])work(p[u],fav); 81 return; 82 } 83 //1 84 bool flag=1; 85 fav++; 86 int dj=ask(1,seg[x],0,100000,0,fav); 87 if(dj<dep[x]+fav)flag=0; //dep[v]+val[v]>=dep[now]+val[now]-->dep[v]-dep[now]>=val[now]-val[v] 88 //printf("__+ %d\n",dj); 89 dj=ask(0,seg[x],0,100000,fav,100000); //dep[v]-val[v]>=dep[now]-val[now]-->dep[v]-dep[now]>=val[v]-val[now] 90 //printf("__+ %d\n",dj); 91 if(dj<dep[x]-fav)flag=0; 92 if(flag){ 93 key[x]=fav; 94 for(int u=head[x];u;u=np[u])if(p[u]^fa[x])work(p[u],fav); 95 return; 96 } 97 //-1 98 fav-=2; 99 flag=1; 100 dj=ask(1,seg[x],0,100000,0,fav); 101 if(dj<dep[x]+fav)flag=0; 102 dj=ask(0,seg[x],0,100000,fav,100000); 103 if(dj<dep[x]-fav)flag=0; 104 if(flag){ 105 key[x]=fav; 106 for(int u=head[x];u;u=np[u])if(p[u]^fa[x])work(p[u],fav); 107 return; 108 } 109 } 110 int main(){ 111 rep(i,0,1)mi[0][i]=1e9; 112 scanf("%d",&n); 113 rep(i,1,n-1){ 114 int a,b;scanf("%d%d",&a,&b); 115 ++tot;p[tot]=b;np[tot]=head[a];head[a]=tot; 116 ++tot;p[tot]=a;np[tot]=head[b];head[b]=tot; 117 } 118 scanf("%d",&K); 119 rep(i,1,n)key[i]=-10000000; 120 rep(i,1,K){ 121 int v,p;scanf("%d%d",&v,&p); 122 key[v]=p; 123 root=v; 124 } 125 dfs(root); 126 work(root,10086); 127 rep(i,1,n)if(i!=root)if(abs(key[i]-key[fa[i]])!=1){ 128 printf("No\n"); 129 return 0; 130 } 131 printf("Yes\n"); 132 rep(i,1,n)printf("%d\n",key[i]); 133 return 0; 134 }