1. 程式人生 > >Codeforces 627D Preorder Test(二分+樹形DP)

Codeforces 627D Preorder Test(二分+樹形DP)

bug eof scan pla k個結點 comment 最大 tdi tac

題意:給出一棵無根樹,每個節點有一個權值,現在要讓dfs序的前k個結點的最小值最大,求出這個值。

考慮二分答案,把>=答案的點標記為1,<答案的點標記為0,現在的任務時使得dfs序的前k個節點都為1.

考慮樹形DP。

用dp[u]表示從節點u開始在子樹中進行dfs最多可以經過多少個為1的結點,顯然,若某一個子樹中節點全為1,那麽這個可以加到dp[u]中,此外還可以在不全為1的子樹中挑選一個加到dp[u]上。

那麽答案就是從標記為1的節點當做根,選兩顆不完全子樹和所有的完全子樹(包括從父親向上的部分)。

那麽如果從父親向上的部分是不完全子樹呢,那等價於從這顆不完全子樹上的一個深度最小的點做上面的計算一下。所以不需要考慮從父親向上的部分是不完全子樹這個情況。

時間復雜度O(nlogn).

技術分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include 
<algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p
<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0,f=1;char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f; } const int N=200005; //Code begin... struct Edge{int p, next;}edge[N<<1]; int node[N], head[N], cnt=1, dp[N], date[N], siz[N], tag[N], sum, n, K, ans; bool flag[N]; void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;} void dfs1(int x, int fa, int val){ siz[x]=1; if (node[x]<val) tag[x]=1, ++sum; if (node[x]<val) flag[x]=true; for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; if (v==fa) continue; dfs1(v,x,val); siz[x]+=siz[v]; tag[x]+=tag[v]; flag[x]|=flag[v]; } } void dfs2(int x, int fa, int val){ dp[x]=1; int f=0, s=0; for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; if (v==fa) continue; dfs2(v,x,val); if (!flag[v]) dp[x]+=siz[v]; else if (node[v]>=val) { if (dp[v]>f) s=f, f=dp[v]; else if (dp[v]>s) s=dp[v]; } } dp[x]+=f; if (node[x]>=val) { if (tag[x]==sum) ans=max(ans,dp[x]+s+n-siz[x]); else ans=max(ans,dp[x]+s); } } bool check(int x){ mem(siz,0); mem(dp,0); mem(flag,false); mem(tag,0); sum=ans=0; dfs1(1,0,x); dfs2(1,0,x); return ans>=K; } int main () { int u, v; scanf("%d%d",&n,&K); FOR(i,1,n) scanf("%d",node+i), date[i]=node[i]; FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u); sort(date+1,date+n+1); int l=1, r=n+1, mid; while (l<r) { mid=(l+r)>>1; if (l==mid) break; if (check(date[mid])) l=mid; else r=mid; } printf("%d\n",date[l]); return 0; }
View Code

Codeforces 627D Preorder Test(二分+樹形DP)