P3696,玄妙的贪心题

来源:互联网 发布:ubuntu 16.10 更新源 编辑:程序博客网 时间:2024/06/13 22:24

首先把中场的每个团体看做左括号。结束时的每个团体看做右括号。然后按照人气值从小到大排序(实际上因为初始输入就有序,可以用归并来代替排序)。

这样我们就得到了一个括号序列。每个括号都有一个颜色(即其学校编号)。然后要删掉尽量多的同色括号对,并使得剩下的括号序列仍然合法。

从左往右考虑每个括号,一开始花了一个下午想了五种O(n)贪心,一一拍炸,然而拍炸前总觉得是对的。这里就不赘述这些贪心了。

一个无所作为的下午告诉我,O(n)的贪心是不行的,这就启示我们用数据结构去优化。

将左括号视为1,右括号视为-1,那么一个合法的括号序列,其所有前缀和一定非负。

考虑删掉一对括号对前缀和的影响,这相当于对前缀和区间减。

然而要保证前缀和非负,所以减的区间中,最小值要大于零。

考虑一个右括号能否找到与之匹配,且一起删掉后合法的左括号。记ss为这个右括号以左第一个为零的前缀和所在的位置,那么左括号一定要在那个位置以右,并且二者同色。

用线段树实现区间加和区间最小值,查询ss时二分,就得到了优越拙劣的O(nlog2n)做法,实际上有O(nlogn)的题解,但实际效率好像还不错。

另外说一句,这道题里票数可以为零,这,坑了我很久,甚至对拍也拍不出。以后还是要注意,这个错误把我坑到45分(其中25分是常数太大)

#include<cstdio>#include<cctype>#include<vector>const int N=400010,L=1000000;char ibuf[L],*ih=ibuf+L;inline char gc(){return ih==ibuf+L?fread(ibuf,1,L,stdin),ih=ibuf,*ih++:*ih++;}inline void read(int&x){    static char c;    for(c=gc();!isdigit(c);c=gc());    for(x=0;isdigit(c);c=gc())x=x*10+c-48;}std::vector<int> s[N];int n,i,j,ans,ss,aa[N],bb[N],xb,ea[N],eb[N],l,r,m;struct person{int x,y;}a[N],b[N];inline int min(int a,int b){return a>b?b:a;}struct segtree{    struct node{        int l,r,m,s,mn;    }t[N<<2];    void build(int i,int l,int r){        t[i].l=l,t[i].r=r;t[i].m=(l+r)>>1;        if(l==r)return;build(i<<1,l,t[i].m),build(i<<1|1,t[i].m+1,r);    }    inline void add(int i,int l,int r,int v){        if(t[i].l==l && t[i].r==r)t[i].s+=v,t[i].mn+=v;            else{                if(t[i].m<l)add(i<<1|1,l,r,v);                    else if(r<=t[i].m)add(i<<1,l,r,v);                            else add(i<<1,l,t[i].m,v),add(i<<1|1,t[i].m+1,r,v);                t[i].mn=(t[i<<1].mn>t[i<<1|1].mn?t[i<<1|1].mn:t[i<<1].mn)+t[i].s;            }    }    inline int query(int i,int l,int r){        if(t[i].l==l && t[i].r==r)return t[i].mn;        return (r<=t[i].m?query(i<<1,l,r):(l>t[i].m?query(i<<1|1,l,r):min(query(i<<1,l,t[i].m),            query(i<<1|1,t[i].m+1,r))))+t[i].s;    }}t;int main(){    read(n);ans=n;t.build(1,1,n<<1);    for(i=1;i<=n;++i)read(a[i].x),read(a[i].y);    for(i=1;i<=n;++i)read(b[i].x),read(b[i].y);s[b[1].x].push_back(1);aa[xb=1]=1;bb[1]=1;    t.add(1,1,n<<1,1);eb[1]=1;b[n+1].y=-1;    for(i=j=1;i<=n;++i){        while(b[j+1].y>=a[i].y)++j,aa[eb[j]=++xb]=j,s[b[j].x].push_back(xb),bb[xb]=1,            t.add(1,xb,n<<1,1);        aa[ea[i]=++xb]=i,bb[xb]=-1;t.add(1,xb,n<<1,-1);        for(l=ss,r=xb-1;l<r;){            m=(l+r+1)>>1;            if(t.query(1,m,xb-1))r=m-1;                else l=m;        }        ss=l;        if(!s[a[i].x].empty() && s[a[i].x].back()>ss)--ans,t.add(1,s[a[i].x].back(),ea[i]-1,-1),            s[a[i].x].pop_back();    }    printf("%d\n",ans);    return 0;}