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