这题一眼就看出可以用树套树来做,但是打起来好麻烦,常数还大,所以只打了30分。
其实,这是一道裸的cdq分治,把询问拆成[l,mid]和[mid+1,r],[l,mid]的修改会对[mid+1,r]的修改产生影响。
cdq分治就是二分时间,然后处理完左边对右边的影响,然后继续往下递归。
记录一个点被多少个矩阵覆盖,首先如果矩阵的标号是(x,y,xx,yy),那么拆成两个点,一个点有3个信息:横坐标,控制的纵坐标区间,和操作分类(1、插入,2、询问,3、删除,按这个顺序),然后以横坐标为第一关键字,操作分类为第二关键字排序。
插入控制的区间在下端点打个+1的标记,上端点+1的位置打一个-1的标记,同样在删除的时候,下端点打个-1的标记,上端点+1的位置打一个+1的标记。
然后需要询问这个节点左下角所有标记之和。
我们首先已经控制了横坐标,然后先进行插入在进行询问,现在需要维护纵坐标的值。
那么只用树状数组来操作就好了。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=8e5+7;
int i,j,k,l,n,m,cas,z,x,y,xx,yy,num,num1;
int t[maxn],ans[maxn];
struct node{
int x,y,xx,yy,c,bz;
}a[maxn],b[maxn];
int lowbit(int x){return x&(-x);}
void add(int x,int y){
for(;x<=maxn-7;x+=lowbit(x))t[x]+=y;
}
int find(int x){
int z=0;
for(;x;x-=lowbit(x))z+=t[x];
return z;
}
bool cmp(node x,node y){return x.xvoid dfs(int l,int r){
if(l==r)return;
int mid=(l+r)/2;
int i;num=0;
fo(i,l,mid)if(!b[i].bz){
a[++num]=(node){b[i].x,b[i].y,b[i].x,b[i].yy,0,-5};
a[++num]=(node){b[i].xx,b[i].y,b[i].xx,b[i].yy,0,5};
}
fo(i,mid+1,r)if(b[i].bz){
a[++num]=(node){b[i].x,b[i].y,0,0,b[i].c,0};
}
sort(a+1,a+1+num,cmp);
fo(i,1,num){
if(a[i].bz==0)ans[a[i].c]+=find(a[i].y);
else if(a[i].bz==-5)add(a[i].y,1),add(a[i].yy+1,-1);
else add(a[i].y,-1),add(a[i].yy+1,1);
}
dfs(l,mid),dfs(mid+1,r);
}
int main(){
scanf("%d",&cas);
fo(i,1,cas){
scanf("%d",&z);
if(!z){
scanf("%d%d%d%d",&x,&y,&xx,&yy);x++,y++,xx++,yy++;
b[i]=(node){x,y,xx,yy,i,0};
}
else{
scanf("%d%d",&x,&y);x++,y++;
b[i]=(node){x,y,0,0,i,1};
}
}
dfs(1,cas);
fo(i,1,cas)if(b[i].bz)printf("%d\n",ans[i]);
}