相交区间选尽量少的点是可以贪心的,右端点排序以后,尽量往右边放可以得到可以使得点在区间尽可能多。
但是我只想到了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; }