【BZOJ2674】Attack(整体二分+树状数组套线段树)

点此看题面

大致题意: 一个二维平面上有(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('
');}
		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.
");//大于最大值说明无解
	return F.clear(),0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2674.html