传送门
对于每一个点,维护(i,j)可以采到但是(i+1,j)不能采到的花的数量f[i][j]。
那么对于每一只牛,答案就应为f[i][j]+f[i+1][j]+……+f[k][j],k为i向下遇到的第一个栅栏。我们称这个答案为“从点(i,j)出发的答案”。
区间的操作很容易想到线段树,我们考虑扫描线。从右向左扫,用线段树维护列上的答案。遇到一个花(i,j)就相当于在线段树的i位置+1,遇到一头牛(i,j)就查询从这个点出发的答案。如果遇到一个栅栏的右边界,假设边界的范围是(i1,j)(i2,j),那么应该求出[i1,i2]的答案,然后加到i1-1去。如果遇到一个栅栏的左边界,假设边界的范围是(i1,j1)(i2,j1),且当前栅栏的右边界的范围是(i3,j2)(i4,j2)那么应该将[i1,i2]段清零,并且在点i1-1减去从点(i4+1,j2)出发的答案。本质上是个差分。
对于扫到的同一列,维护的顺序问题需要注意,并且细节问题比较多。
#include
#include
#include
#include
using namespace std;
const int N=2e5+5;
const int LOC=1e6+5;
const int NN=N*10;
const int T=LOC*4;
int f,m,n,maxr,maxc,cnt;
int r1[N],c1[N],r2[N],c2[N],fr[N],fc[N],cor[N],coc[N],nearby[N],Nearby[N],last[N],Ans[N];
struct hp{int r1,r2,c1,c2,r,c,id,ty;}a[NN];
inline int in()
{
char ch=getchar(); int x=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void out(int x)
{
if (x==0)
{
putchar('0');
putchar('\n');
return;
}
int now=0;
int print[10];
while (x>0)
{
print[++now]=x%10;
x/=10;
}
for (int i=now;i>=1;--i) putchar(print[i]+'0');
putchar('\n');
return;
}
inline int cmp1(hp a,hp b){return a.cinline int cmp2(hp a,hp b){return a.c>b.c||(a.c==b.c&&a.tynamespace Junior
{
int lef[T];
inline void update(int now)
{
lef[now]=min(lef[now<<1],lef[now<<1|1]);
}
inline void build(int now,int l,int r)
{
int mid=(l+r)>>1;
if (l==r)
{
lef[now]=maxr+1;
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
inline void point_change(int now,int l,int r,int x,int v)
{
int mid=(l+r)>>1;
if (l==r)
{
if (v==1) lef[now]=l;
else lef[now]=maxr+1;
return;
}
if (x<=mid) point_change(now<<1,l,mid,x,v);
else point_change(now<<1|1,mid+1,r,x,v);
update(now);
}
inline int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=maxr+1;
if (lrange<=l&&r<=rrange) return lef[now];
if (lrange<=mid) ans=min(ans,query(now<<1,l,mid,lrange,rrange));
if (mid+1<=rrange) ans=min(ans,query(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
}
namespace Senior
{
int sum[T],delta[T];
inline void update(int now)
{
sum[now]=sum[now<<1]+sum[now<<1|1];
}
inline void pushdown(int now,int l,int r,int mid)
{
if (delta[now]!=-1)
{
sum[now<<1]=delta[now]; delta[now<<1]=delta[now];
sum[now<<1|1]=delta[now]; delta[now<<1|1]=delta[now];
delta[now]=-1;
}
}
inline void point_change(int now,int l,int r,int x,int v)
{
int mid=(l+r)>>1;
if (l==r)
{
sum[now]+=v;
return;
}
pushdown(now,l,r,mid);
if (x<=mid) point_change(now<<1,l,mid,x,v);
else point_change(now<<1|1,mid+1,r,x,v);
update(now);
}
inline void interval_cover(int now,int l,int r,int lrange,int rrange,int v)
{
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange)
{
sum[now]=v;
delta[now]=v;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid) interval_cover(now<<1,l,mid,lrange,rrange,v);
if (mid+1<=rrange) interval_cover(now<<1|1,mid+1,r,lrange,rrange,v);
update(now);
}
inline int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=0;
if (lrange<=l&&r<=rrange) return sum[now];
pushdown(now,l,r,mid);
if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange);
return ans;
}
}
int main()
{
f=in();
for (int i=1;i<=f;++i)
{
r1[i]=in(); c1[i]=in(); r2[i]=in(); c2[i]=in();
maxr=max(maxr,r1[i]); maxr=max(maxr,r2[i]);
maxc=max(maxc,c1[i]); maxc=max(maxc,c2[i]);
}
m=in();
for (int i=1;i<=m;++i)
{
fr[i]=in(); fc[i]=in();
maxr=max(maxr,fr[i]); maxc=max(maxc,fc[i]);
}
n=in();
for (int i=1;i<=n;++i)
{
cor[i]=in(); coc[i]=in();
maxr=max(maxr,cor[i]); maxc=max(maxc,coc[i]);
}
cnt=0;
for (int i=1;i<=f;++i)
{
if (r1[i]!=1) a[++cnt].r=r1[i]-1,a[cnt].c=c1[i],a[cnt].ty=1,a[++cnt].r=r1[i]-1,a[cnt].c=c2[i],a[cnt].ty=4;
a[++cnt].r=r2[i],a[cnt].c=c1[i],a[cnt].ty=1,a[++cnt].r=r2[i],a[cnt].c=c2[i],a[cnt].ty=4;
if (c2[i]!=maxc) a[++cnt].r=r1[i],a[cnt].c=c2[i]+1,a[cnt].ty=3,a[cnt].id=i;
}
for (int i=1;i<=n;++i) a[++cnt].r=cor[i],a[cnt].c=coc[i],a[cnt].ty=2,a[cnt].id=i;
sort(a+1,a+cnt+1,cmp1);
Junior::build(1,1,maxr);
for (int i=1;i<=cnt;++i)
{
switch(a[i].ty)
{
case 1://左栅栏
{
Junior::point_change(1,1,maxr,a[i].r,1);
break;
}
case 2://牛
{
nearby[a[i].id]=Junior::query(1,1,maxr,a[i].r,maxr);
if (nearby[a[i].id]==maxr+1) nearby[a[i].id]=maxr;
break;
}
case 3://栅栏的右上角
{
Nearby[a[i].id]=Junior::query(1,1,maxr,a[i].r,maxr);
if (Nearby[a[i].id]==maxr+1) Nearby[a[i].id]=maxr;
break;
}
case 4://右栅栏
{
Junior::point_change(1,1,maxr,a[i].r,-1);
break;
}
}
}
cnt=0;
for (int i=1;i<=f;++i)
{
a[++cnt].r1=r1[i],a[cnt].c1=c1[i],a[cnt].r2=r2[i],a[cnt].c2=c1[i],a[cnt].ty=4,a[cnt].id=i;
a[cnt].r=a[cnt].r1,a[cnt].c=a[cnt].c1;
if (c2[i]!=maxc)
{
a[++cnt].r1=r1[i],a[cnt].c1=c2[i]+1,a[cnt].r2=r2[i],a[cnt].c2=c2[i]+1,a[cnt].ty=3,a[cnt].id=i;
a[cnt].r=a[cnt].r1,a[cnt].c=a[cnt].c1;
}
}
for (int i=1;i<=m;++i) a[++cnt].r=fr[i],a[cnt].c=fc[i],a[cnt].ty=1;
for (int i=1;i<=n;++i) a[++cnt].r=cor[i],a[cnt].c=coc[i],a[cnt].ty=2,a[cnt].id=i;
sort(a+1,a+cnt+1,cmp2);
memset(Senior::delta,-1,sizeof(Senior::delta));
for (int i=1;i<=cnt;++i)
{
switch(a[i].ty)
{
case 1://花
{
Senior::point_change(1,1,maxr,a[i].r,1);
break;
}
case 2://牛
{
int ans=Senior::query(1,1,maxr,a[i].r,nearby[a[i].id]);
Ans[a[i].id]=ans;
break;
}
case 3://右栅栏
{
if (a[i].r2!=maxr) last[a[i].id]=Senior::query(1,1,maxr,a[i].r2+1,Nearby[a[i].id]);
int ans=Senior::query(1,1,maxr,a[i].r1,Nearby[a[i].id]);
if (a[i].r1!=1) Senior::point_change(1,1,maxr,a[i].r1-1,ans);
Senior::interval_cover(1,1,maxr,a[i].r1,a[i].r2,0);
break;
}
case 4://左栅栏
{
Senior::interval_cover(1,1,maxr,a[i].r1,a[i].r2,0);
if (a[i].r1!=1) Senior::point_change(1,1,maxr,a[i].r1-1,-last[a[i].id]);
break;
}
}
}
for (int i=1;i<=n;++i)
out(Ans[i]);
1、一定要想好了再写。
2、代码能力太弱= =