ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一类经典的树形染色问题

2021-08-12 02:01:37  阅读:194  来源: 互联网

标签:ch int 染色 sum long 树形 经典 include getchar


题目

1. 2种做法,一种是 $O(nk\log n)$,另一种是 $O(n)$。前者可以从深度大的开始填(优先队列维护)。后者只需要开 $f[0][x]$ 表示 $x$ 离关键点的最近距离,$f[1][x]$ 表示 $x$ 离没被控制的最远点的距离。考虑 $f[0][x]+f[1][x] \le k$ ,$x$ 就能被控制。$f[1][x]=k$,$x$ 就要成为关键点。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <map>
 9  
10 #define ll long long
11  
12 using namespace std;
13 int rd() {
14     int f=1,sum=0; char ch=getchar();
15     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
16     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
17     return sum*f;
18 }
19 ll lrd() {
20     ll f=1,sum=0; char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
23     return sum*f;
24 }
25 
26 const int N=(int)(1e5+5);
27 struct edge {
28     int nex,to;
29 }e[N<<1];
30 struct node {
31     int val,id;
32     bool operator < (const node &x) const {
33         return val<x.val;
34     }
35     bool operator > (const node &x) const {
36         return val>x.val;
37     }
38 };
39 priority_queue<node>q;
40 bool vis[N];
41 int head[N],cnt,dep[N],fa[N];
42 int n,m;
43 
44 void add_edge(int x,int y) {
45     e[++cnt]=(edge){head[x],y}; head[x]=cnt;
46 }
47 
48 void dfs1(int x,int ff) {
49     for(int i=head[x];i;i=e[i].nex) {
50         int y=e[i].to;
51         if(dep[y]) continue;
52         fa[y]=x; dep[y]=dep[x]+1;
53         dfs1(y,x);
54     }
55 }
56 
57 void dfs2(int x,int ff,int num) {
58     //cout<<x<<" "<<num<<endl;
59     vis[x]=1; if(!num) return ;
60     for(int i=head[x];i;i=e[i].nex) {
61         int y=e[i].to;
62         if(y==ff) continue;
63         dfs2(y,x,num-1);
64     } 
65 }
66 
67 int main() {
68     int x,y;
69     n=rd(); m=rd(); rd();
70     for(int i=1;i<n;i++) {
71         x=rd(); y=rd(); add_edge(x,y); add_edge(y,x);
72     }
73     fa[1]=1; dep[1]=1; dfs1(1,1);
74     for(int i=1;i<=n;i++) q.push((node){dep[i],i});
75     int ans=0;
76     while(!q.empty()) {
77         int x=q.top().id; q.pop();
78         if(vis[x]) continue;
79         vis[x]=1; ++ans; 
80         for(int i=1;i<=m;i++) x=fa[x];
81         dfs2(x,x,m);
82     }
83     printf("%d",ans);
84     return 0;
85 } 
View Code

2. 考虑二分,然后把非关键点就不要计入贡献,即只需要让这些非关键点满足$f[0][x]+f[1][x] \le k$ 即可。那么初始化改下 $f[1]$ 就好。 dp 过程对于关键点的 $f[1]$ 要对 0 取个max。即也许最远没被控制的是它自己。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <map>
 9 
10 #define ll long long
11 
12 using namespace std;
13 int rd() {
14     int f=1,sum=0; char ch=getchar();
15     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
16     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
17     return sum*f;
18 }
19 ll lrd() {
20     ll f=1,sum=0; char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
23     return sum*f;
24 }
25 // f[0][x] x到关键点的最小距离 f[1][x] x到最远未控制点的距离 
26 const int N=(int)(3e5+5);
27 struct edge {
28     int nex,to;
29 }e[N<<1];
30 int f[2][N],col[N],head[N],cnt,n,m,K,ans;
31 
32 void add_edge(int x,int y) {
33     e[++cnt]=(edge){head[x],y}; head[x]=cnt;
34 }
35 
36 void dfs(int x,int ff) {
37     for(int i=head[x];i;i=e[i].nex) {
38         int y=e[i].to;
39         if(y==ff) continue;
40         dfs(y,x);
41         f[1][x]=max(f[1][x],f[1][y]+1);
42         f[0][x]=min(f[0][x],f[0][y]+1);
43     }
44     if(col[x]) f[1][x]=max(f[1][x],0);
45     if(f[0][x]+f[1][x]<=K) f[1][x]=-0x3f3f3f3f;
46     if(f[1][x]==K) {
47         f[1][x]=-0x3f3f3f3f; f[0][x]=0; ++ans;
48     } 
49     if(x==1) if(f[0][x]+f[1][x]>K) ++ans;
50 }
51 
52 bool check(int x) {
53     memset(f[0],0x3f,sizeof(f[0])); memset(f[1],-0x3f,sizeof(f[1]));
54 //    cout<<f[1][0]<<endl;
55     K=x; ans=0;
56     dfs(1,0);
57     return ans<=m; 
58 }
59 
60 int main() {
61     int x,y;
62     n=rd(); m=rd();
63     for(int i=1;i<=n;i++) col[i]=rd();
64     for(int i=1;i<n;i++) {
65         x=rd(); y=rd(); add_edge(x,y); add_edge(y,x); 
66     }
67     int l=0,r=n,res=0;
68     while(l<=r) {
69         int mid=(l+r)>>1;
70         if(check(mid)) res=mid,r=mid-1;
71         else l=mid+1;
72     } 
73     printf("%d",res);
74     return 0;
75 }
View Code

3. 树形 dp,solution 在注释里面。至于为什么 k 要正序枚举,因为一开始的时候必须加上子树全为白色情况。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <map>
 9 
10 #define ll long long
11 
12 using namespace std;
13 int rd() {
14     int f=1,sum=0; char ch=getchar();
15     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
16     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
17     return sum*f;
18 }
19 ll lrd() {
20     ll f=1,sum=0; char ch=getchar();
21     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22     while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
23     return sum*f;
24 }
25 /*
26 f[x][k] 表示在x点 其中x的子树有k个黑点 sz[x]-k个白点的最大收益
27 ans=f[1][k]
28 考虑经过 y-x 这条边的点对数量
29 考虑y中选v个黑点 
30  v*(k-v)个点对
31 白点: (sz[y]-v)*(n-k-(sz[y]-v))
32 树上背包 
33 */ 
34 const int N=2002;
35 struct edge {
36     int nex,to,w;
37 }e[N<<1];
38 ll f[N][N];
39 int head[N],sz[N],cnt,n,m;
40 
41 void add_edge(int x,int y,int z) {
42     e[++cnt]=(edge){head[x],y,z}; head[x]=cnt;
43 }
44 
45 void dfs(int x,int ff) {
46     sz[x]=1; memset(f[x],-1,sizeof(f[x])); f[x][0]=0;
47     for(int i=head[x];i;i=e[i].nex) {
48         int y=e[i].to;
49         if(y==ff) continue;
50         dfs(y,x); sz[x]+=sz[y];
51     }
52     for(int i=head[x];i;i=e[i].nex) {
53         int y=e[i].to;
54         if(y==ff) continue;
55         for(int j=min(sz[x],m);j>=0;j--) {
56             for(int k=0;k<=min(sz[y],j);k++) {
57                 if(f[x][j-k]<0) continue;
58                 ll val=1ll*e[i].w*k*(m-k)+1ll*e[i].w*(sz[y]-k)*(n-m-(sz[y]-k));
59             //    cout<<val<<endl;
60                 f[x][j]=max(f[x][j],f[x][j-k]+f[y][k]+val);
61             }
62         }
63     }
64 }
65 
66 int main() {
67     int x,y,z;
68     n=rd(); m=rd();
69     for(int i=1;i<n;i++) x=rd(),y=rd(),z=rd(),add_edge(x,y,z),add_edge(y,x,z);
70     dfs(1,0);
71     printf("%lld",f[1][m]);
72 }
View Code

 

标签:ch,int,染色,sum,long,树形,经典,include,getchar
来源: https://www.cnblogs.com/xugangfan/p/15130923.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有