Problem A Circuits(选两点与最多线段相交 线段树)

http://codeforces.com/gym/101987/attachments A

题意: 给出多个线段,你选择两个点,与最多的线段相交(与两个点相交只算一次)。

解析: 随着第一个点的后移,第二个点需要考虑的线段越来越少,如果按照左端点排序,发现每次被第一个点解除的线段从前往后。所以只需要考虑每个后缀的最优策略即可。

代码:

#include
using namespace std;

#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int maxn=3e5+9;

struct node{
    int l,r;
    bool operator<(const node&A)const{
        return l<A.l;
    }
}e[maxn];

struct Uni{
    int num;
    int tmp[maxn];
    void push(int x){
        tmp[++num]=x;
    }
    void init(){
        sort(tmp+1,tmp+1+num);
        num=unique(tmp+1,tmp+1+num)-tmp-1;
    }
    int idx(int val){
        return lower_bound(tmp+1,tmp+1+num,val)-tmp;
    }
    int ori(int idx){
        return tmp[idx];
    }
}U;
/*_________________________________________________________unique*/

int tr[maxn<<2];//max
int laz[maxn<<2];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define root int rt,int l,int r
#define lson ls,l,mid
#define rson rs,mid+1,r
void down(root){
    if(laz[rt]){
        laz[ls]+=laz[rt];
        laz[rs]+=laz[rt];
        tr[ls]+=laz[rt];
        tr[rs]+=laz[rt];
        laz[rt]=0;
    }
}
void update(root,int L,int R,int v){
    if(l>=L&&r<=R){
        tr[rt]+=v;
        laz[rt]+=v;
        return;
    }
    down(rt,l,r);
    if(L<=mid)update(lson,L,R,v);
    if(R>mid)update(rson,L,R,v);
    tr[rt]=max(tr[ls],tr[rs]);
}
int query(root,int L,int R){
    if(l>=L&&r<=R){
        return tr[rt];
    }
    down(rt,l,r);
    int ans=0;
    if(L<=mid)ans=query(lson,L,R);
    if(R>mid)ans=max(ans,query(rson,L,R));
    return ans;
}

int ct[maxn];
int mx;
int ans[maxn];
int main(){
    int n;scanf("%d",&n);
    int _;
    rep(i,1,n){
        scanf("%d%d%d%d",&_,&e[i].r,&_,&e[i].l);
        U.push(e[i].l);
        U.push(e[i].r);
    }
    U.init();
    mx=U.num;
    rep(i,1,n)e[i].l=U.idx(e[i].l),e[i].r=U.idx(e[i].r);
    rep(i,1,n){
        ct[e[i].l]++;
        ct[e[i].r+1]--;
    }
    rep(i,1,mx)ct[i]+=ct[i-1];
    sort(e+1,e+1+n);
    per(i,n,1){
        update(1,1,mx,e[i].l,e[i].r,1);
        ans[i]=query(1,1,mx,1,mx);
    }
    ans[n+1]=0;
    int ar=1;
    int Ans=0;
    for(int i=1;i<=mx;i++){
        while(ar<=n&&e[ar].l<=i)ar++;
        Ans=max(Ans,ct[i]+ans[ar]);
    }
    printf("%d\n",Ans);
}

你可能感兴趣的:(数据结构)