BZOJ4369: [IOI2015]teams分组

41 篇文章 0 订阅
4 篇文章 0 订阅

将一个人(A,B)视作一个二维平面上的点,则一个小组k可以看作是[0,k]x[k,+∞]的一个矩形
对于每个询问,我们从小到大处理k,每次将当前的可行区域内最低的那些点分配给k,对于不可行或之前取过的点的矩形区域,我们维护他们的拐点,这些拐点从左到右高度递减,用一个单调栈维护,查询矩形内点数可以用主席树
总复杂度 O((n+s)logn) O ( ( n + s ) l o g n )

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 1010000;
const int maxp = 21000000;

int n,m;
struct Point{ int x,y; }p[maxn];
int yi[maxn];
namespace Trans
{
    struct node
    {
        int x; int *i;
        friend inline bool operator <(const node x,const node y){return x.x<y.x;}
    }a[maxn];
    struct data
    {
        int x,i;
        friend inline bool operator <(const data x,const data y){return x.x<y.x;}
    };
    set<data>tox,toy;
    set<data>::iterator it;
    void main()
    {
        for(int i=1;i<=n;i++)
        {
            if(p[i].x<0) p[i].x=1;
            if(p[i].y>n) p[i].y=n;
        }

        for(int i=1;i<=n;i++) a[i]=(node){p[i].x,&p[i].x};
        sort(a+1,a+n+1); a[n+1].x=a[n].x-1;
        for(int i=1;i<=n;i++)
        {
            (*a[i].i)=i;
            if(a[i].x!=a[i+1].x) tox.insert((data){a[i].x,i});
        }

        for(int i=1;i<=n;i++) a[i]=(node){p[i].y,&p[i].y};
        sort(a+1,a+n+1); a[0].x=a[1].x-1;
        for(int i=1;i<=n;i++)
        {
            (*a[i].i)=i;
            if(a[i].x!=a[i-1].x) toy.insert((data){a[i].x,i});
        }

        for(int i=1;i<=n;i++) yi[p[i].x]=p[i].y;
    }
    Point q(int k)
    {
        Point re;
        it=tox.upper_bound((data){k,0});
        if(it==tox.begin()) return (Point){-1,-1};
        it--; re.x=(*it).i;
        it=toy.lower_bound((data){k,0});
        if(it==toy.end()) return (Point){-1,-1};
        re.y=(*it).i;
        return re;
    }
}
struct Segment
{
    int cnt;
    int seg[maxp],lc[maxp],rc[maxp];
    int root[maxn];
    int loc;
    void upd(int &x,const int l,const int r)
    {
        x=++cnt; seg[x]=1;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(loc<=mid) upd(lc[x],l,mid);
        else upd(rc[x],mid+1,r);
    }
    void merge(int &x,const int &y)
    {
        if(!y) return;
        if(!x) { x=y; return; }
        seg[x]+=seg[y];
        merge(lc[x],lc[y]); merge(rc[x],rc[y]);
    }
    void build()
    {
        for(int i=1;i<=n;i++)
        {
            loc=yi[i]; upd(root[i],1,n);
            merge(root[i],root[i-1]);
        }
    }
    int lx,rx;
    int query(const int x,const int y,const int l,const int r)
    {
        if(rx<l||r<lx||seg[x]==seg[y]) return 0;
        if(lx<=l&&r<=rx) return seg[y]-seg[x];
        int mid=(l+r)>>1;
        return query(lc[x],lc[y],l,mid)+query(rc[x],rc[y],mid+1,r);
    }
    int q(int l,int r,int d,int u)
    {
        lx=d,rx=u;
        if(lx>n) return 0;
        if(lx<=rx) return query(root[l-1],root[r],1,n);
        return 0;
    }
    int queryi(const int x,const int y,const int l,const int r,int &k)
    {
        if(rx<l||r<lx) return -1;
        int mid=(l+r)>>1;
        if(lx<=l&&r<=rx)
        {
            if(k>seg[y]-seg[x]) { k-=seg[y]-seg[x]; return -1; }
            else
            {
                if(l==r) return l;
                int re=queryi(lc[x],lc[y],l,mid,k);
                return re!=-1?re:re=queryi(rc[x],rc[y],mid+1,r,k);
            }
        }
        int re=queryi(lc[x],lc[y],l,mid,k);
        return re!=-1?re:re=queryi(rc[x],rc[y],mid+1,r,k);
    }
    int qi(int l,int r,int d,int u,int k)
    {
        lx=d,rx=u;
        return queryi(root[l-1],root[r],1,n,k);
    }
}seg;

Point t[maxn]; int tp;
int q[maxn],qn;

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    read(n);
    for(int i=1;i<=n;i++) read(p[i].x),read(p[i].y);
    Trans::main();
    seg.build();

    read(m);
    while(m--)
    {
        read(qn); ll num=0;
        for(int i=1;i<=qn;i++) read(q[i]),num+=q[i];
        if(num>n) { puts("0"); continue; }
        sort(q+1,q+qn+1);

        int ok=1;
        t[tp=0]=(Point){0,n+1};
        for(int i=1;i<=qn&&ok;i++)
        {
            Point temp=Trans::q(q[i]);
            if(temp.x==-1) { ok=0;break; }

            if(t[tp].x<temp.x) t[++tp]=(Point){temp.x,temp.y};
            else t[tp].y=max(t[tp].y,temp.y);
            while(tp&&t[tp-1].y<=t[tp].y) t[tp-1]=t[tp],tp--;

            int oth=q[i];
            while(oth)
            {
                if(!tp) { ok=0;break; }
                int sum=seg.q(t[tp-1].x+1,t[tp].x,t[tp].y,t[tp-1].y-1);
                if(oth>sum)
                {
                    oth-=sum;
                    t[tp-1].x=t[tp].x; tp--;
                }
                else
                {
                    int y=seg.qi(t[tp-1].x+1,t[tp].x,t[tp].y,t[tp-1].y-1,oth);
                    t[tp].y=y+1;
                    if(t[tp].y==t[tp-1].y) t[tp-1]=t[tp],tp--;
                    break;
                }
            }
        }
        putchar('0'+ok);
        putchar('\n');
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值