这题的思路还是挺巧妙的
最关键的一步是我们改求与当前矩形不相交的矩形个数
那么显然可以容斥,用完全在上面的+下面的+左面的+右面的-四个角上被重复算的
前面的四个比较好搞,以上面举例,插入矩形时把矩形的下边界插入树状数组,查询时抓住当前矩形的上边界在树状数组里查就好了
四个角的部分,以左上角为例,插入矩形时把矩形的右下角记录下来,查询时查矩形的左上角的左上方有多少个点
所以现在相当于要实现在平面里面加点删点,然后求一个矩形区域内有多少个点
考虑到cc没有空间限制,刚开始无脑上了动态开点二维线段树,拼命卡常,把线段树换成非递归的又把外层线段树换成树桩才过
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
const double pi=acos(-1);
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
struct BIT
{
int c[400048];
inline void init() {memset(c,0,sizeof(c));}
inline void update(int x,int lim,int delta) {while (x<=lim) c[x]+=delta,x+=LOWBIT(x);}
inline int query(int x) {int res=0;while (x) res+=c[x],x-=LOWBIT(x);return res;}
}up,down,lft,rght;
int n,itot1,itot2;
int ind[100048],indtot=0;
struct Query
{
int type;
int x1,y1,x2,y2,t;
int nx1,ny1,nx2,ny2;
}a[100048];
struct point
{
int val;
int from;bool type;
inline bool operator < (const point &x) const {return val<x.val;}
}b[500048];int btot;
namespace SegmentTree
{
int tree[5][(330+5)*200048];
int lson[(330+5)*200048],rson[(330+5)*200048];int tot=0;
int lis[100048],litot=0;
inline void updatey(int cur,int type,int pos,int delta,int l,int r)
{
litot=0;
while (l<=r)
{
lis[++litot]=cur;
if (l==r) break;
int mid=(l+r)>>1;
if (pos<=mid)
{
if (!lson[cur]) lson[cur]=++tot;
cur=lson[cur];r=mid;
}
else
{
if (!rson[cur]) rson[cur]=++tot;
cur=rson[cur];l=mid+1;
}
}
for (register int i=litot;i>=1;i--) tree[type][lis[i]]+=delta;
}
int List[100048],ltot=0;
inline void updatex(int type,int x,int y,int delta,int r)
{
while (x<=r)
{
updatey(x,type,y,delta,1,itot2);
x+=LOWBIT(x);
}
}
int qy[5000048],qyhead,qytail;
inline int queryy(int cur,int type,int left,int right,int l,int r)
{
qyhead=1;qytail=3;qy[1]=l;qy[2]=r;qy[3]=cur;int res=0,curleft,curright,cc,mid;
while (qyhead<=qytail)
{
curleft=qy[qyhead++];curright=qy[qyhead++];cc=qy[qyhead++];
if (left<=curleft && curright<=right) {res+=tree[type][cc];continue;}
mid=(curleft+curright)>>1;
if (left<=mid) qy[++qytail]=curleft,qy[++qytail]=mid,qy[++qytail]=lson[cc];
if (mid+1<=right) qy[++qytail]=mid+1,qy[++qytail]=curright,qy[++qytail]=rson[cc];
}
return res;
}
inline int Query(int x,int y1,int y2,int type)
{
int res=0;
while (x)
{
res+=queryy(x,type,y1,y2,1,itot2);
x-=LOWBIT(x);
}
return res;
}
inline int queryx(int type,int x1,int x2,int y1,int y2)
{
if (x1>x2 || y1>y2) return 0;
return Query(x2,y1,y2,type)-Query(x1-1,y1,y2,type);
}
}
int main ()
{
freopen ("a.in","r",stdin);
freopen ("a.ans","w",stdout);
int i;n=getint();string type;
for (i=1;i<=n;i++)
{
cin>>type;
if (type=="I") a[i].type=1;
if (type=="D") a[i].type=2;
if (type=="Q") a[i].type=3;
if (a[i].type==1 || a[i].type==3) a[i].x1=getint(),a[i].y1=getint(),a[i].x2=getint(),a[i].y2=getint();
else a[i].t=getint();
}
btot=0;
for (i=1;i<=n;i++)
if (a[i].type!=2) b[++btot]=point{a[i].x1,i,false},b[++btot]=point{a[i].x2,i,true};
sort(b+1,b+btot+1);itot1=0;
for (i=1;i<=btot;i++)
{
if (i==1 || b[i].val!=b[i-1].val) itot1++;
if (!b[i].type) a[b[i].from].nx1=itot1; else a[b[i].from].nx2=itot1;
}
btot=0;
for (i=1;i<=n;i++)
if (a[i].type!=2) b[++btot]=point{a[i].y1,i,false},b[++btot]=point{a[i].y2,i,true};
sort(b+1,b+btot+1);itot2=0;
for (i=1;i<=btot;i++)
{
if (i==1 || b[i].val!=b[i-1].val) itot2++;
if (!b[i].type) a[b[i].from].ny1=itot2; else a[b[i].from].ny2=itot2;
}
int pt=0,cnt=0,exist=0;
up.init();down.init();lft.init();rght.init();
SegmentTree::tot=itot1*4;
for (i=1;i<=n;i++)
{
if (a[i].type==1)
{
exist++;ind[++indtot]=i;
down.update(a[i].ny2,itot2,1);
up.update(itot2-a[i].ny1+1,itot2,1);
lft.update(a[i].nx2,itot1,1);
rght.update(itot1-a[i].nx1+1,itot1,1);
SegmentTree::updatex(1,a[i].nx2,a[i].ny1,1,itot1);
SegmentTree::updatex(2,a[i].nx1,a[i].ny1,1,itot1);
SegmentTree::updatex(3,a[i].nx2,a[i].ny2,1,itot1);
SegmentTree::updatex(4,a[i].nx1,a[i].ny2,1,itot1);
}
if (a[i].type==2)
{
exist--;pt=ind[a[i].t];
down.update(a[pt].ny2,itot2,-1);
up.update(itot2-a[pt].ny1+1,itot2,-1);
lft.update(a[pt].nx2,itot1,-1);
rght.update(itot1-a[pt].nx1+1,itot1,-1);
SegmentTree::updatex(1,a[pt].nx2,a[pt].ny1,-1,itot1);
SegmentTree::updatex(2,a[pt].nx1,a[pt].ny1,-1,itot1);
SegmentTree::updatex(3,a[pt].nx2,a[pt].ny2,-1,itot1);
SegmentTree::updatex(4,a[pt].nx1,a[pt].ny2,-1,itot1);
}
if (a[i].type==3)
{
int curcnt=0;
curcnt+=down.query(a[i].ny1-1);
curcnt+=up.query(itot2-a[i].ny2);
curcnt+=lft.query(a[i].nx1-1);
curcnt+=rght.query(itot1-a[i].nx2);
curcnt-=SegmentTree::queryx(1,1,a[i].nx1-1,a[i].ny2+1,itot2);
curcnt-=SegmentTree::queryx(2,a[i].nx2+1,itot1,a[i].ny2+1,itot2);
curcnt-=SegmentTree::queryx(3,1,a[i].nx1-1,1,a[i].ny1-1);
curcnt-=SegmentTree::queryx(4,a[i].nx2+1,itot1,1,a[i].ny1-1);
printf("%d\n",exist-curcnt);
}
}
return 0;
}
后来发现这个东西其实就是一个三维偏序,时间是第一维,坐标是二三维,所以可以用cdq分治+树状数组来搞,时间复杂度一样但是编码难度和常数都很优秀
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
const double pi=acos(-1);
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
struct BIT
{
int c[400048];
inline void init() {memset(c,0,sizeof(c));}
inline void update(int x,int lim,int delta) {while (x<=lim) c[x]+=delta,x+=LOWBIT(x);}
inline void clear(int x,int lim) {while (x<=lim) c[x]=0,x+=LOWBIT(x);}
inline int query(int x) {int res=0;while (x) res+=c[x],x-=LOWBIT(x);return res;}
}up,down,lft,rght,CDQ;
struct Query
{
int type;
int x1,y1,x2,y2;
int nx1,nx2,ny1,ny2;
}a[100048];
struct C
{
int type;
int x,y,ind;
}c[100048],tmp[100048];
struct point
{
int val;
int from;bool type;
inline bool operator < (const point &x) const {return val<x.val;}
}b[500048];int btot;
int n,itot1,itot2;
int ind[100048],indtot=0;
int ans[100048];
int history[100048],htot;
inline void cdq(int left,int right)
{
if (left==right) return;
int mid=(left+right)>>1,k1,k2,pt;
cdq(left,mid);cdq(mid+1,right);htot=0;
for (k1=left,k2=mid+1,pt=left;k1<=mid && k2<=right;)
{
if (c[k1].x<=c[k2].x)
{
if (c[k1].type==1) CDQ.update(c[k1].y,itot2,1),history[++htot]=c[k1].y;
if (c[k1].type==2) CDQ.update(c[k1].y,itot2,-1),history[++htot]=c[k1].y;
tmp[pt++]=c[k1++];
}
else
{
if (c[k2].type==3) ans[c[k2].ind]+=CDQ.query(c[k2].y);
tmp[pt++]=c[k2++];
}
}
while (k1<=mid) tmp[pt++]=c[k1++];
while (k2<=right)
{
if (c[k2].type==3) ans[c[k2].ind]+=CDQ.query(c[k2].y);
tmp[pt++]=c[k2++];
}
for (register int i=left;i<=right;i++) c[i]=tmp[i];
for (register int i=1;i<=htot;i++) CDQ.clear(history[i],itot2);
}
int main ()
{
//freopen ("a.in","r",stdin);
//freopen ("a.out","w",stdout);
int i,x;n=getint();string type;
for (i=1;i<=n;i++)
{
cin>>type;
if (type=="I")
{
ind[++indtot]=i;
a[i].x1=getint();a[i].y1=getint();a[i].x2=getint();a[i].y2=getint();
a[i].type=1;
}
if (type=="D")
{
x=getint();
a[i]=a[ind[x]];a[i].type=2;
}
if (type=="Q")
{
a[i].x1=getint();a[i].y1=getint();a[i].x2=getint();a[i].y2=getint();
a[i].type=3;
}
}
btot=0;
for (i=1;i<=n;i++) b[++btot]=point{a[i].x1,i,false},b[++btot]=point{a[i].x2,i,true};
sort(b+1,b+btot+1);itot1=0;
for (i=1;i<=btot;i++)
{
if (i==1 || b[i-1].val!=b[i].val) itot1++;
if (!b[i].type) a[b[i].from].nx1=itot1; else a[b[i].from].nx2=itot1;
}
btot=0;
for (i=1;i<=n;i++) b[++btot]=point{a[i].y1,i,false},b[++btot]=point{a[i].y2,i,true};
sort(b+1,b+btot+1);itot2=0;
for (i=1;i<=btot;i++)
{
if (i==1 || b[i-1].val!=b[i].val) itot2++;
if (!b[i].type) a[b[i].from].ny1=itot2; else a[b[i].from].ny2=itot2;
}
up.init();down.init();lft.init();rght.init();
int exist=0;
for (i=1;i<=n;i++)
{
if (a[i].type==1)
{
exist++;
down.update(a[i].ny2,itot2,1);
up.update(itot2-a[i].ny1+1,itot2,1);
lft.update(a[i].nx2,itot1,1);
rght.update(itot1-a[i].nx1+1,itot1,1);
}
if (a[i].type==2)
{
exist--;
down.update(a[i].ny2,itot2,-1);
up.update(itot2-a[i].ny1+1,itot2,-1);
lft.update(a[i].nx2,itot1,-1);
rght.update(itot1-a[i].nx1+1,itot1,-1);
}
if (a[i].type==3)
{
ans[i]=exist;
ans[i]-=down.query(a[i].ny1-1);
ans[i]-=up.query(itot2-a[i].ny2);
ans[i]-=lft.query(a[i].nx1-1);
ans[i]-=rght.query(itot1-a[i].nx2);
}
}
//up-left
for (i=1;i<=n;i++)
{
if (a[i].type==1 || a[i].type==2) c[i]=C{a[i].type,a[i].nx2,itot2-a[i].ny1+1}; else c[i]=C{3,a[i].nx1-1,itot2-a[i].ny2};
c[i].ind=i;
}
cdq(1,n);
//up-right
for (i=1;i<=n;i++)
{
if (a[i].type==1 || a[i].type==2) c[i]=C{a[i].type,itot1-a[i].nx1+1,itot2-a[i].ny1+1};
else c[i]=C{3,itot1-a[i].nx2,itot2-a[i].ny2};
c[i].ind=i;
}
cdq(1,n);
//down-left
for (i=1;i<=n;i++)
{
if (a[i].type==1 || a[i].type==2) c[i]=C{a[i].type,a[i].nx2,a[i].ny2};
else c[i]=C{3,a[i].nx1-1,a[i].ny1-1};
c[i].ind=i;
}
cdq(1,n);
//down-right
for (i=1;i<=n;i++)
{
if (a[i].type==1 || a[i].type==2) c[i]=C{a[i].type,itot1-a[i].nx1+1,a[i].ny2};
else c[i]=C{3,itot1-a[i].nx2,a[i].ny1-1};
c[i].ind=i;
}
cdq(1,n);
for (i=1;i<=n;i++)
if (a[i].type==3) printf("%d\n",ans[i]);
return 0;
}