大致题意: 一个二维平面上有\(n\)个带权点,要求支持两种操作:交换两点点权;询问一个区域的第\(k\)小值。
前言
可怕的树套树。。。
对着一个点调了二十几分钟,不过幸好调过这个点之后就过了,还是挺舒服的。
大致思路
考虑第\(k\)小值这种东西很难搞,而这道题又没有强制在线,因此首先就考虑整体二分。
而整体二分时,交换可以拆成两个删除、两个插入。
于是问题就变得很简单了:在二维平面上每次加入或删除一个点,询问一个区域内的点数。
这就有很多乱七八糟的家伙可以维护了:树状数组套线段树、二维线段树、\(KD-Tree\)。。。
想到很久没有写过树套树了,于是写了一发树状数组套线段树,感觉其实也不会很难写。
代码
#pragma GCC optimize(2)
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 60000
#define M 10000
#define SZ (N+4*M)
#define LN 20
#define swap(x,y) (x^=y^=x^=y)
using namespace std;
int n,m,cnt,X[N+5],Y[N+5],V[N+5];struct Data
{
int p,k,x,y,a,b;I Data() {p=k=x=y=a=b=0;}
I Data(CI i,CI t,CI p,CI q):p(i),k(t),x(p),y(q){}
I Data(CI i,CI t,CI p,CI q,CI u,CI v):
p(i),k(t),x(p),y(q),a(u),b(v){x>a&&swap(x,a),y>b&&swap(y,b);}
}s[SZ+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
I void readc(char& x) {W(isspace(x=tc()));}
Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('\n');}
I void writes(Con string& x) {for(RI i=0,l=x.length();i^l;++i) pc(x[i]);}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
struct Discretization//离散化
{
int dc,dv[N+2*M+5];I int& operator [] (CI x) {return dv[x];}
I void Init(CI x) {sort(dv+1,dv+x+1),dc=unique(dv+1,dv+x+1)-dv-1;}
I int operator () (CI x) {return lower_bound(dv+1,dv+dc+1,x)-dv;}
}Dx,Dy,Dv;
class SegmentArray//树状数组套线段树
{
private:
int Rt[N+2*M+5];
class Segment
{
private:
#define PU(x) (O[x].V=O[O[x].S[0]].V+O[O[x].S[1]].V)
#define LT O[rt].S[0],l,mid
#define RT O[rt].S[1],mid+1,r
int Nt;struct node {int V,S[2];}O[N*LN*LN+5];
public:
I void U(CI x,CI v,int& rt,CI l=1,CI r=Dy.dc)//单点修改
{
if(!rt&&(rt=++Nt),l==r) return (void)(O[rt].V+=v);int mid=l+r>>1;
x<=mid?U(x,v,LT):U(x,v,RT),PU(rt);
}
I int Q(CI L,CI R,CI rt,CI l=1,CI r=Dy.dc)//区间查询
{
if(!rt||(L<=l&&r<=R)) return O[rt].V;int mid=l+r>>1;
return (L<=mid?Q(L,R,LT):0)+(R>mid?Q(L,R,RT):0);
}
}S;
I int Q(RI x,CI l,CI r) {RI t=0;W(x) t+=S.Q(l,r,Rt[x]),x-=x&-x;return t;}
public:
I void U(RI x,CI y,CI v) {W(x<=Dx.dc) S.U(y,v,Rt[x]),x+=x&-x;}//单点修改
I int Q(CI x,CI y,CI a,CI b) {return Q(a,y,b)-Q(x-1,y,b);}//矩形查询
}T;
class WholeSolver//整体二分
{
private:
Data sl[SZ+5],sr[SZ+5];
public:
int ans[M+5];
I void Solve(CI l,CI r,CI L,CI R)
{
RI i,tl=0,tr=0,fl=0,fr=0;if(l==r||L>R) {for(i=L;i<=R;++i) ans[s[i].p]=l;return;}//处理边界
RI t,mid=l+r>>1;for(i=L;i<=R;++i)
{
if(!s[i].p)//对于修改
{
(abs(s[i].k)<=mid?T.U(s[i].x,s[i].y,s[i].k>0?1:-1),sl[++tl]:sr[++tr])=s[i];
continue;
}
((t=T.Q(s[i].x,s[i].y,s[i].a,s[i].b))>=s[i].k?//对于询问
fl=1,sl[++tl]:(fr=1,s[i].k-=t,sr[++tr]))=s[i];
}
for(i=L;i<=R;++i) !s[i].p&&abs(s[i].k)<=mid&&(T.U(s[i].x,s[i].y,s[i].k>0?-1:1),0);//清空
for(i=1;i<=tl;++i) s[L+i-1]=sl[i];for(i=1;i<=tr;++i) s[L+tl+i-1]=sr[i];
fl&&(Solve(l,mid,L,L+tl-1),0),fr&&(Solve(mid+1,r,L+tl,R),0);//递归
}
}S;
int main()
{
RI i,x,y,a,b,v;for(F.read(n,m),i=1;i<=n;++i)//读入点
F.read(X[i],Y[i],V[i]),Dx[i]=X[i],Dy[i]=Y[i],Dv[i]=V[i];//离散化数组记下对应信息
for(Dv.Init(n),i=1;i<=n;++i) s[++cnt]=Data(0,V[i]=Dv(V[i]),X[i],Y[i]);//把初始点视作修改
RI Qt=0,p,q;char op;for(i=1;i<=m;++i)//读入操作
F.readc(op),F.read(x,y),op=='Q'?F.read(a,b,v),++Qt,s[++cnt]=
Data(Qt,v,Dx[n+2*Qt-1]=x,Dy[n+2*Qt-1]=y,Dx[n+2*Qt]=a,Dy[n+2*Qt]=b),0//存储询问
:(
++x,++y,s[++cnt]=Data(0,-V[x],X[x],Y[x]),s[++cnt]=Data(0,-V[y],X[y],Y[y]),//把交换视作两个删除、两个插入
s[++cnt]=Data(0,V[y],X[x],Y[x]),s[++cnt]=Data(0,V[x],X[y],Y[y]),swap(V[x],V[y])
);
for(Dx.Init(n+2*Qt),Dy.Init(n+2*Qt),i=1;i<=cnt;++i)//离散化坐标
s[i].x=Dx(s[i].x),s[i].y=Dy(s[i].y),s[i].a=Dx(s[i].a),s[i].b=Dy(s[i].b);
for(S.Solve(1,Dv.dc+1,1,cnt),i=1;i<=Qt;++i)//输出答案
S.ans[i]<=Dv.dc?F.writeln(Dv[S.ans[i]]):F.writes("It doesn't exist.\n");//大于最大值说明无解
return F.clear(),0;
}