zoukankan      html  css  js  c++  java
  • Codeforces 627D Preorder Test(二分+树形DP)

    题意:给出一棵无根树,每个节点有一个权值,现在要让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
    ",date[l]);
        return 0;
    }
    View Code
  • 相关阅读:
    【转载】数据结构与算法设计
    【转载】简述Linux的启动过程
    【转载】20分钟MySQL基础入门
    【转载】linux内核笔记之进程地址空间
    【转载】linux内核笔记之高端内存映射
    Logical Address->Linear Address->Physical Address
    【转载】教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
    【转载】不会编程也能写爬虫?可视化爬虫工具是什么东东
    【转载】我是一个键盘
    80. Remove Duplicates from Sorted Array II
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6971255.html
Copyright © 2011-2022 走看看