传送门是不可能有的了
题解:
联赛组今天考试的T3,觉得很有科学打脸价值就来写一写。
首先正解是一个需要四棵线段树的 O ( n log n + m log n ) O(n\log n+m\log n) O(nlogn+mlogn)做法,常数巨大。
本着科学打脸观。我写了一个 O ( ( n + m ) n ) O((n+m)\sqrt n) O((n+m)n)跑过了大多数人的线段树。
其实卡常就是按照常规卡了一下,莫名其妙就跑进了 3 s 3s 3s以内。
由于加的东西是单调的,所以我们用最后的渔网的横纵坐标将平面切割成九块。
但是实际上只有左下角四块的点需要考虑,设立四个边界。
每块维护一下下一次出现需要跨边界的点需要加多少 x x x和 y y y。
每个点最多跨越三次边界,在块中出现点跨越边界的时候重构整块,每个点对所在块的重构次数贡献是 O ( 1 ) O(1) O(1)的,每次重构复杂度是 O ( n ) O(\sqrt n) O(n)的,单个块重构的均摊复杂度为 O ( n ) ∗ O ( n ) = O ( n ) O(\sqrt n)*O(\sqrt n)=O(n) O(n)∗O(n)=O(n)。一共有 O ( n ) O(\sqrt n) O(n)块,总复杂度为 O ( n n ) O(n\sqrt n) O(nn)
散块的修改也可以需要直接重构。每次最多重构两块,复杂度为 O ( m n ) O(m\sqrt n) O(mn)
由于散块的重构是卡满了的,缩小块长就可以轻易卡下常数。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;bool f=0;
while(!isdigit(c=gc()))f=c=='-';T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=3e4+5;
#define x1 x_1
#define x2 x_2
#define y1 y_1
#define y2 y_2
int n,m;
int x1,x2,y1,y2;
int B,bcnt;
int bl[N],pl[N],pr[N],ans[N];
int x[N],y[N],addx[N],addy[N],nxtx[N],nxty[N];
inline void rebuild(int id){
ans[id]=0;nxtx[id]=0x3f3f3f3f,nxty[id]=0x3f3f3f3f;
for(int re i=pl[id];i<=pr[id];++i){
x[i]+=addx[id],y[i]+=addy[id];
if(x[i]>x2||y[i]>y2)continue;
(x1<=x[i]&&x[i]<=x2&&y1<=y[i]&&y[i]<=y2)&&(++ans[id]);
nxtx[id]=std::min(nxtx[id],x[i]<x1?x1-x[i]:x2+1-x[i]);
nxty[id]=std::min(nxty[id],y[i]<y1?y1-y[i]:y2+1-y[i]);
}
addx[id]=addy[id]=0;
}
inline void modify_x(int l,int r,int d){
if(bl[l]==bl[r]){
for(int re i=l;i<=r;++i)x[i]+=d;
rebuild(bl[l]);
return ;
}
if(l==pl[bl[l]])--l;
else {
for(int re i=l;i<=pr[bl[l]];++i)x[i]+=d;
rebuild(bl[l]);
}
if(r==pr[bl[r]])++r;
else {
for(int re i=r;i>=pl[bl[r]];--i)x[i]+=d;
rebuild(bl[r]);
}
for(int re i=bl[l]+1;i<bl[r];++i)if((addx[i]+=d)>=nxtx[i])rebuild(i);
}
inline void modify_y(int l,int r,int d){
if(bl[l]==bl[r]){
for(int re i=l;i<=r;++i)y[i]+=d;
rebuild(bl[l]);
return ;
}
if(l==pl[bl[l]])--l;
else {
for(int re i=l;i<=pr[bl[l]];++i)y[i]+=d;
rebuild(bl[l]);
}
if(r==pr[bl[r]])++r;
else {
for(int re i=r;i>=pl[bl[r]];--i)y[i]+=d;
rebuild(bl[r]);
}
for(int re i=bl[l]+1;i<bl[r];++i)if((addy[i]+=d)>=nxty[i])rebuild(i);
}
inline int query(int l,int r){int res=0;
if(bl[l]==bl[r]){
if(l==pl[bl[l]]&&r==pr[bl[r]])res=ans[bl[l]];
else {
for(int re i=l,dx=addx[bl[l]],dy=addy[bl[l]];i<=r;++i)
res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
}
return res;
}
if(l==pl[bl[l]])res+=ans[bl[l]];
else{
for(int re i=l,dx=addx[bl[l]],dy=addy[bl[l]];i<=pr[bl[l]];++i)
res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
}
if(r==pr[bl[r]])res+=ans[bl[r]];
else {
for(int re i=r,dx=addx[bl[r]],dy=addy[bl[r]];i>=pl[bl[r]];--i)
res+=(x1<=x[i]+dx&&x[i]+dx<=x2&&y1<=y[i]+dy&&y[i]+dy<=y2);
}
for(int re i=bl[l]+1;i<bl[r];++i)res+=ans[i];
return res;
}
inline void solve(){
n=getint(),x1=getint(),y1=getint(),x2=getint(),y2=getint();
B=std::max(1.0,sqrt(n)*0.3);bcnt=0;
for(int re i=1;i<=n;++i){
x[i]=getint(),y[i]=getint();
if((i-1)%B==0){
pl[++bcnt]=i;pr[bcnt-1]=i-1;
addx[bcnt]=addy[bcnt]=ans[bcnt]=0;
}
bl[i]=bcnt;
}bl[n+1]=bcnt+1;
for(int re i=1;i<=bcnt;++i)rebuild(i);
m=getint();int l,r,d;
while(m--)switch(getint()){
case 1:l=getint(),r=getint(),d=getint();modify_x(l,r,d);break;
case 2:l=getint(),r=getint(),d=getint();modify_y(l,r,d);break;
case 3:l=getint(),r=getint();cout<<query(l,r)<<"\n";break;
}
}
signed main(){
// freopen("fish.in","r",stdin);//freopen("fish.out","w",stdout);
int T=getint();
while(T--)solve();
return 0;
}