XOJ 2011 fly飞机 题解
首先根据题意,我们可将每组人化成一段线段在1~n 的数轴上。
①从1~n,从当我们选择右端点靠左的区间的时候方案更优,可以通过画线段图来直观感觉,对于三个相邻线段,右端点靠左的线段设它为第 i 段,后面两个分别是 i+1, i+2,当我们选择 i 的时候,它与 i+2 相交的可能性小于 i+1 ,所以我们不需要牺牲 i 的人数来选择 i+1 的人。所以我们只需要根据各个线段右端点的位置从小到大排序,每次取靠左的。通过线段树维护。
②从n~1的反之,根据左端点排序,操作时可将它反过来类似右端点操作。
#include <iostream>
#include <cstdio>
#include <algorithm>
#define _(d) while(d (((ch=getchar())>47)&&ch<58))
#define L(x) (x<<1)
#define R(x) ((x<<1)+1)
using namespace std;
const int Maxk=50005;
const int Maxn=10005;
int k,n,c,tt1,tt2,ans;
inline void Get(int &x){char ch;_(!);x=ch-48;_()x=(x<<3)+(x<<1)+ch-48;}
struct Bnode
{
int a,b,c;
}s1[Maxk],s2[Maxk];
struct Btree
{
int mx,lf,rt;
}t[Maxn<<2];
inline void build(int num,int l,int r)
{
t[num].lf=l;t[num].rt=r;
t[num].mx=0;
if(l+1==r) return;
int mid=(l+r)>>1;
build(L(num),l,mid);
build(R(num),mid,r);
}
inline void update(int num)
{
t[num].mx=max(t[L(num)].mx,t[R(num)].mx);
}
inline void insert(int l,int r,int num,int v)
{
if(t[num].lf+1==t[num].rt) {t[num].mx+=v;return ;}
int mid=(t[num].lf+t[num].rt)>>1;
if(r<=mid) insert(l,r,L(num),v);
else if(l>=mid) insert(l,r,R(num),v);
else
{
insert(l,mid,L(num),v);
insert(mid,r,R(num),v);
}
update(num);
}
inline int query(int l,int r,int num)
{
if(l==t[num].lf&&r==t[num].rt) return t[num].mx;
int mid=(t[num].lf+t[num].rt)>>1;
if(r<=mid) return query(l,r,L(num));
if(l>=mid) return query(l,r,R(num));
else
{
return max(query(l,mid,L(num)),query(mid,r,R(num)));
}
}
inline bool Bcmp1(const Bnode x,const Bnode y){return x.b<y.b;}
inline bool Bcmp2(const Bnode x,const Bnode y){return x.a>y.a;}
inline void getans(int f)
{
build (1,1,n+1);
int tt=f?tt1:tt2;
if(f)
for(int i=1;i<=tt;i++)
{
int tmp=0;
tmp=query(s1[i].a,s1[i].b,1);
tmp=max(0,c-tmp);
tmp=min(s1[i].c,tmp);
if(tmp>0)
{
ans+=tmp;
insert(s1[i].a,s1[i].b,1,tmp);
}
}
else
for(int i=1;i<=tt;i++)
{
int tmp=0;
tmp=query(s2[i].a,s2[i].b,1);
tmp=max(0,c-tmp);
tmp=min(s2[i].c,tmp);
if(tmp>0)
{
ans+=tmp;
insert(s2[i].a,s2[i].b,1,tmp);
}
}
}
int main()
{
//freopen("2011.in","r",stdin);
int a,b,vv;
Get(k);Get(n);Get(c);
for(int i=1;i<=k;i++)
{
Get(a);Get(b);Get(vv);
if(a<b)
{
s1[++tt1].a=a;
s1[tt1].b=b;
s1[tt1].c=vv;
}
else
{
s2[++tt2].a=b;
s2[tt2].b=a;
s2[tt2].c=vv;
}
}
sort(s1+1,s1+tt1+1,Bcmp1);
sort(s2+1,s2+tt2+1,Bcmp2);
getans(1);
getans(0);printf("%d\n",ans);
return 0;
}