愚蠢的博主又上線啦!
這題博主一看排序+樹狀數組o(n*logn),先分類把天數相同的證件拿一個vector存(拿數組就炸了,vector的話空間就是o(n)了),然後按l第一關鍵字,r第二關鍵字,價值第三關鍵字排序,然後枚舉n個證件,用x減去這個證件的天數,然後在相應的vector內,分兩段l之前和r之後,然後樹狀數組求這兩個區間的最大值。
然後博主非常尷尬wa了一個小時。。
正解是很勁的貪心,掃一遍就行了。。真心想不出來(實際是博主菜)
首先設個數組f[i]表示證件爲i天的最大價值,然後分兩個數組排序(一個按l,一個按r),實際是一個爲第一個證件一個爲第二個證件,因爲兩天不想交肯定有第一個的r小於第二個的l,所以先枚舉按l排序的證,件然後枚舉按r排序的證件第一個的r大於第二個的l,所以對於第一個證件肯定滿足提供f[i]的證件與其不相交(因爲第一個證件日期後面的還沒掃),注意f[i]當且僅當對當前的第一個證件有用,然後在枚舉第二證件的過程中求出f[i](i=[1,i])的值,然後對於ans更新(就是比較ans和第1個證件與其匹配的證件價值和)
UPDATE(7.19):其實這是一個單調棧以第一個證件枚舉,做單調棧
注意:不存在配對的情況輸出-1。
ps:博主調不對那個愚蠢的排序+線段樹了,那就不調了(就是所謂的打不過就加入(黑一發勇士))。
代碼:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int Maxn=2*100005;
const int oo=2147483647;
struct node
{
int l,r,v,d;
}days_A[Maxn],days_B[Maxn];
int f[Maxn];
int cmp_A(node a,node b)
{
return a.l<b.l;
}
int cmp_B(node a,node b)
{
return a.r<b.r;
}
int main()
{
int n,x,ans=oo;
scanf("%d%d",&n,&x);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&days_A[i].l,&days_A[i].r,&days_A[i].v);
days_A[i].d=days_A[i].r-days_A[i].l+1;
days_B[i]=days_A[i];
}
for(int i=0;i<=x;i++)
f[i]=oo;
sort(days_A+1,days_A+n+1,cmp_A);
sort(days_B+1,days_B+n+1,cmp_B);
int j=0;
for(int i=1;i<=n;i++)
{
while(j<=n&&days_A[i].l>days_B[j].r)
{
f[days_B[j].d]=min(f[days_B[j].d],days_B[j].v);
j++;
}
if(x-days_A[i].d>0&&f[x-days_A[i].d]!=oo)
ans=min(ans,f[x-days_A[i].d]+days_A[i].v);
}
printf("%d",(ans==oo)?-1:ans);
return 0;
}