CF627D Preorder Test

题意:给你一棵树,你可以选择开始的根和遍历儿子的顺序,求按照选定顺序的dfs遍历的前k个点的min{ai}最大。

标程:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=200005;
 5 int n,cnt,head[N],fa[N],sz[N],k,Max,f[N],a[N],u,v,l,r,size[N],ans,b[N];
 6 struct node{int to,next;}num[N*2];
 7 void add(int x,int y)
 8 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
 9 void dfs_pre(int x)
10 {
11     sz[x]=1;
12     for (int i=head[x];i;i=num[i].next)
13       if (num[i].to!=fa[x])
14       {
15             fa[num[i].to]=x;
16             dfs_pre(num[i].to);
17             sz[x]+=sz[num[i].to];
18       }
19 }
20 void dfs(int x,int mid)
21 {
22     size[x]=(a[x]>=mid);int ans=1,mx=0,mxc=0;
23     for (int i=head[x];i;i=num[i].next)
24       if (num[i].to!=fa[x]) 
25       {
26            dfs(num[i].to,mid);
27            size[x]+=size[num[i].to];
28          if (size[num[i].to]==sz[num[i].to]) ans+=sz[num[i].to];
29            else if (f[num[i].to]>mx) mxc=mx,mx=f[num[i].to];
30            else if (f[num[i].to]>mxc) mxc=f[num[i].to];
31       }
32     if (a[x]<mid) f[x]=0;else f[x]=ans+mx;
33     if (cnt-size[x]==n-sz[x]) ans+=n-sz[x];//这里不能用size[1],因为还没处理啊 
34     if (a[x]>=mid) Max=max(Max,ans+mx+mxc);
35 }
36 bool check(int mid)
37 {
38     Max=0;cnt=lower_bound(b+1,b+n+1,mid)-b-1;cnt=n-cnt;
39     dfs(1,mid);
40     return Max>=k;
41 }
42 int main() 
43 {
44     scanf("%d%d",&n,&k);
45     for (int i=1;i<=n;i++) scanf("%d",&a[i]),Max=max(Max,a[i]),b[i]=a[i];
46     for (int i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
47     sort(b+1,b+n+1);
48     dfs_pre(1);
49     l=1;r=ans=Max;
50     while (l<=r)
51     {
52         int mid=(l+r)>>1;
53         if (check(mid)) ans=mid,l=mid+1;else r=mid-1;
54     }
55     printf("%d
",ans);
56     return 0;
57 }

易错点:1.这里不能用size[1],因为还没处理啊。所以用一个lower_bound算有多少个数>=mid。

题解:二分答案+树形dp

答案显然有可二分性,对于一个mid,将>=mid的点标黑。

check就是找到一段连续dfs序的点问是否>=k。

枚举每一个点统计根在其子树中的答案,找其子树中有多少个满块(可以遍历满),以及最大和次大的非满块。

而对于其子树外的那一块,只用考虑其为满块的情况。(如果不是满块,那么可以追溯到该点到根的链上的另一点,该点满足子树外的满,或是走不下去。那时这种情况会被统计。)

那么答案就是当当前点为黑点时,满块+最大+次大+1(当前点)。根不一定是当前点,而是从非满块的一个端点开始。

原文地址:https://www.cnblogs.com/Scx117/p/8795121.html