• 【LOJ】 #2521. 「FJOI2018」领导集团问题


    题解

    这道题很显然可以想出来一个(n^2)的dp,也就是dp[u][i]表示以u为根的子树最大值是i的点集最大是多少(i是离散化后的值)

    就是对于每个儿子处理出后缀最大值然后按位相加更新父亲,我们把最大值处理成差分来存储,儿子们的最大值按位相加等于差分按位相加,后缀最大值出现了变化仅当加入了父亲节点形成一个点集,也就是父亲节点的值w[u],所在的位置,跳过差分一串连续的0,遇到第一个有数的值,然后减掉,可以用map

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <map>
    #include <queue>
    //#define ivorysi
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define mo 974711
    #define MAXN 200005
    #define eps 1e-3
    #define RG register
    #define calc(x) __builtin_popcount(x)
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    struct node {
        int to,next;
    }E[MAXN * 2];
    int head[MAXN],sumE,N,w[MAXN],a[MAXN],tot;
    map<int,int> dp[MAXN];
    void add(int u,int v) {
        E[++sumE].to = v;E[sumE].next = head[u];head[u] = sumE;
    } 
    void merge(int u,int v) {
        if(dp[u].size() < dp[v].size()) swap(dp[u],dp[v]);
        for(auto k : dp[v]) dp[u][k.fi] += k.se;
        dp[v].clear();
    }
    void dfs(int u,int fa) {
        for(int i = head[u] ; i ;i = E[i].next) {
    	int v = E[i].to;
    	if(v != fa) {
    	    dfs(v,u);
    	    merge(u,v);
    	}
        }
        map<int,int>::iterator k = dp[u].begin();
        if(k->fi >= w[u]) return;
        k = dp[u].lower_bound(w[u]);--k;
        if(k->se == 1) dp[u].erase(k);else k->se -= 1;
    }
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) read(w[i]),a[i] = w[i];
        sort(a + 1,a + N + 1);
        tot = unique(a + 1,a + N + 1) - a - 1;
        for(int i = 1 ; i <= N ; ++i) w[i] = lower_bound(a + 1,a + tot + 1,w[i]) - a;
        for(int i = 1 ; i <= N ; ++i) dp[i][w[i]] = 1;
        int u;
        for(int i = 2 ; i <= N ; ++i) {
    	read(u);
    	add(u,i);add(i,u);
        }
        dfs(1,0);
        int ans = 0;
        for(auto k : dp[1]) ans += k.se;
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    字符序列(characts)
    装载问题(load)
    哈密顿路
    犯罪团伙
    回溯算法
    维修机器人
    旅行计划
    皇后游戏
    运输
    亲身实测可用的java实现wordxlsxpdf文件下载功能
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9145902.html
Copyright © 2020-2023  润新知