POJ

相交区间选尽量少的点是可以贪心的,右端点排序以后,尽量往右边放可以得到可以使得点在区间尽可能多。

但是我只想到了O(n)的维护方法。(数据比较水,能过...

或者是前缀和可以写sum(bi) - sum(ai-1) ≥ ci

再加上前缀和的单调性 sum(i) - sum(i-1) ≥ 0

以及一个点只能选一次 sum(i-1) - sum(i) ≥ -1。

左边具有可加性的,根据对偶性:min ( sum(n) - sum(0) ) ≥ max( c )

右边就是求一个最长路了。

复杂度:O(VE)。

两种复杂度都爆了,还是能过,大力出奇迹。。。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
using namespace std;

typedef long long ll;


const int maxn = 50000+5;
const int maxm = maxn*3;

int dat[2][maxn];
int * const d = dat[0]+1;

int * const hd = dat[1]+1;
int nx[maxm];
int a[maxn], b[maxm], c[maxm];
int ec;

void add_edge(int u, int v, int w)
{
    c[ec] = w;
    b[ec] = v;
    nx[ec] = hd[u];
    hd[u] = ec++;
}

int n;

int q[maxn];
bool inq[maxn];

int spfa(int s, int t)
{
    memset(d+s,0xff,sizeof(int)*(t-s+1));
    int top = 0;
    q[++top] = s; d[s] = 0; inq[s] = true;
    while(top){
        int u = q[top--];
        inq[u] = false;
        for(int i = hd[u]; ~i; i = nx[i]){
            int v = b[i];
            if(d[v] < d[u] + c[i]){
                d[v] = d[u] + c[i];
                if(!inq[v]) {
                    q[++top] = v;
                    inq[v] = true;
                }
            }
        }
    }
    return d[t];
}

void solve()
{
    for(int i = 0; i < n; i++){
        scanf("%d%d%d", a+i, b+i, c+i);
    }
    int s = *min_element(a,a+n)-1, t = *max_element(b,b+n);
    memset(hd+s, 0xff, sizeof(int)*(t-s+1));
    for(int i = 0; i < n; i++){
        nx[i] = hd[--a[i]];
        hd[a[i]] = i;
    }
    ec = n;
    for(int i = s; i < t; i++){
        add_edge(i,i+1,0);
        add_edge(i+1,i,-1);
    }

    printf("%d
", spfa(s,t));
}


//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    while(~scanf("%d",&n)){
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/5004648.html