CF gym102586 L. Yosupo's Algorithm


题面传送门
首先肯定先按\(y\)排个序,然后分治,让分治中心右边的blue对左边的red造成贡献。
\([L,R]\)这个限制不好处理,可以搞出所有可造成贡献的红蓝对然后二维数点。
如果我们将所有二元组都处理出来那么有\(O(n^2)\)对。
观察发现一个结论:被计入答案的二元组一定有一边是最大值。
如果两边都不是最大值,那么将其中某一边换成最大值后,仍能满足任意合法\([L,R]\)且更优。
所以实际上只有\(O(nlogn)\)个有效的二元组。
但是,对于一个区间可能有很多最大值,此时我们只需要最左边与最右边的最大值即可包含所有\([L,R]\)区间。
然后对于每个询问离线后二维数点,时间复杂度\(O(nlog^2n+qlogn)\)
code:

#include
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 100000
#define M 500000
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
using namespace std;const int INF=2e9+7;
int n,m,k,R,Ans[M+5],H,Nx[N+5<<1],Ny[N+5<<1],x,y,Pus;struct Node{int x,y,w,col;}S[N+5<<1];I bool C1(Node x,Node y){return x.y>1;Solve(l,m);Solve(m+1,r);
	for(W=-INF,i=l;i<=m;i++) !S[i].col&&(W=max(W,S[i].w));for(i=l;i<=m;i++) !S[i].col&&S[i].w==W&&(I1=i);for(i=m;i>=l;i--) !S[i].col&&S[i].w==W&&(I2=i);
	if(W>-INF){for(i=m+1;i<=r;i++) S[i].col&&(S1[++H]=(Ques){S[I1].x,S[i].x,W+S[i].w},I1^I2&&(S1[++H]=(Ques){S[I2].x,S[i].x,W+S[i].w},0));}
	for(W=-INF,i=m+1;i<=r;i++) S[i].col&&(W=max(W,S[i].w));for(i=m+1;i<=r;i++) S[i].col&&S[i].w==W&&(I1=i);for(i=r;i>m;i--) S[i].col&&S[i].w==W&&(I2=i);
	if(W>-INF)for(i=l;i<=m;i++) !S[i].col&&(S1[++H]=(Ques){S[i].x,S[I1].x,W+S[i].w},I1^I2&&(S1[++H]=(Ques){S[i].x,S[I2].x,W+S[i].w},0));
}
namespace Tree{
	int F[N+5<<1];I void BD(){for(RI i=1;i<=2*n;i++) F[i]=-INF;}I void Ins(int x,int w){while(x<=2*n) F[x]=max(F[x],w),x+=x&-x;}I int Qry(int x){int Ans=-INF;while(x) Ans=max(Ans,F[x]),x-=x&-x;return Ans;}
}
int main(){
//	freopen("1.in","r",stdin);
	RI i;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d%d",&S[i].x,&S[i].y,&S[i].w),Nx[i]=S[i].x,Ny[i]=S[i].y;for(i=n+1;i<=n*2;i++)scanf("%d%d%d",&S[i].x,&S[i].y,&S[i].w),S[i].col=1,Nx[i]=S[i].x,Ny[i]=S[i].y;sort(S+1,S+2*n+1,C1);
	sort(Nx+1,Nx+n*2+1);sort(Ny+1,Ny+n*2+1);for(i=1;i<=2*n;i++) S[i].x=LB(Nx+1,Nx+2*n+1,S[i].x)-Nx,S[i].y=LB(Ny+1,Ny+2*n+1,S[i].y)-Ny;Solve();scanf("%d",&m);
	for(i=1;i<=m;i++) scanf("%d%d",&x,&y),S2[i]=(Ques){LB(Nx+1,Nx+2*n+1,x)-Nx-1,UB(Nx+1,Nx+2*n+1,y)-Nx,i},Ans[i]=-INF,S3[i]=(Ques){UB(Nx+1,Nx+2*n+1,x)-Nx,LB(Nx+1,Nx+2*n+1,y)-Nx-1,i};sort(S1+1,S1+H+1,C2);
//	for(i=1;i<=H;i++) printf("%d %d %d\n",S1[i].x,S1[i].y,S1[i].w);
	sort(S2+1,S2+m+1,C2);Tree::BD();for(R=i=1;i<=m;i++){while(R<=H&&S2[i].x>=S1[R].x) Tree::Ins(2*n-S1[R].y+1,S1[R].w),R++;Pus=Tree::Qry(2*n-S2[i].y+1);Ans[S2[i].w]=max(Ans[S2[i].w],Pus);}
	sort(S3+1,S3+m+1,C2);Tree::BD();for(R=H,i=m;i;i--){while(R&&S3[i].x<=S1[R].x) Tree::Ins(S1[R].y,S1[R].w),R--;Pus=Tree::Qry(S3[i].y);Ans[S3[i].w]=max(Ans[S3[i].w],Pus);}
	for(i=1;i<=m;i++) printf("%d\n",Ans[i]^(-INF)?Ans[i]:-1);
}