XX Open Cup, Grand Prix of Tokyo D,L

D
二分max值为L,判定能否使用L的数构造出答案。

暂时不管L的限制。此时如果我们有一组解,表示为c0,c1,...,c60,其中ci是有多少个数在第i位为1。那么我们可以将ci2ci14;或者ci4ci+12,构造出所有合法解。(为什么不是ci1ci12呢?因为我们不仅要让sum不变,还要让xor不变,所以加减的数必然是偶数)

那么我们如何构造c?设xi为异或和X的第i位,si为和S的第i位。那么xi=1意味着ci为奇数,也就是ci1,那么我们不妨将X减去S,此时每个数都出现了偶数次,那么我们将其除以二,我们设这样操作后的数为YY=(SX)/2),第i位为yi。不难构造出ci=2yi+xi

L
我们对第一个限制分治,也就是,我们对y坐标从小到大排序,每次分成左右两个区间,并且记录出现在左侧的红点和出现在右侧的蓝点,那么我们就想让红点和蓝点匹配。

直接暴力匹配是O(n2)的(当然也体现不出分治的意义),但是这里有一个结论:最大权值的匹配必然是有一个颜色的点的权值最大。也就是,只能是左侧红点中w最大的和右侧所有蓝点匹配;或者右侧蓝点w最大的和左侧红点匹配。

证明很简单——假设当前我们的询问为[L,R],当前分治的区间为[lef,rig],左半部分为[lef,mid],右半部分为[mid+1,rig]。若LlefrigR,那么区间内所有点对都满足条件2。否则若lefLmidRrig,则左侧最大值和右侧最大值会落到[lef,L1],[L,mid],[mid+1,R],[R+1,rig]这四个区间的两个中,那么根据抽屉原理,我们取1,42,3段时,必然会出现包含左侧最大值或右侧最大值的段。否则就是相交的情况,其实就是将四段变成三段或更少,也是满足条件的。

那么这样点对数就降到O(nlogn)。我们处理出这些点对。回答询问可以让询问离线,将询问和点对按左节点从小往大\从大往小排序,用BIT处理前缀和后缀max即可。具体实现看程序。(有点像扫描线,但这里空间有些大,开线段树很危险,只能用树状数组了)

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=200000,maxq=500005,N=maxn*20+maxq+maxq;
int n,q;
int x[maxn],y[maxn],w[maxn],clr[maxn],id[maxq],ql[maxq],qr[maxq],ans[maxq];
std::vector<int> tmp;
std::vector<std::array<int,3>> points;
std::vector<std::array<int,3>> query;

void divide(int l,int r) {
	if(l==r) return;
	int mid=l+r>>1,mx,rc;
	divide(l,mid); divide(mid+1,r);
	mx=-1;
	for(int i=l;i<=mid;i++) {
		if(mx<w[id[i]]&&clr[id[i]]==1) {
			rc=i;
			mx=w[id[i]];
		}
	}
	if(mx!=-1) {
		for(int i=mid+1;i<=r;i++) {
			if(clr[id[i]]==1) continue;
			int sx=x[id[rc]],tx=x[id[i]],W=w[id[rc]]+w[id[i]]; 
			if(sx>tx) std::swap(sx,tx);
			points.push_back({sx,tx,W});
		}
	}
	mx=-1;
	for(int i=mid+1;i<=r;i++) {
		if(mx<w[id[i]]&&clr[id[i]]==2) {
			rc=i;
			mx=w[id[i]];
		}
	}
	if(mx!=-1) {
		for(int i=l;i<=mid;i++) {
			if(clr[id[i]]==2) continue;
			int sx=x[id[rc]],tx=x[id[i]],W=w[id[rc]]+w[id[i]];
			if(sx>tx) std::swap(sx,tx);
			points.push_back({sx,tx,W});
		}
	}
}

#define lowbit(x) (x&-x) 

struct tree1 {
	int val[N];
	tree1 () {
		memset(val,-1,sizeof val);
	}
	void add(int pos,int num) {
		for(int i=pos;i<N;i+=lowbit(i)) {
			val[i]=std::max(val[i],num);
		}
	}
	int qry(int pos) {
		int ret=-1;
		for(int i=pos;i;i-=lowbit(i)) {
			ret=std::max(ret,val[i]);
		}
		return ret;
	}
}BIT1;

struct tree2 {
	int val[N];
	tree2 () {
		memset(val,-1,sizeof val);
	}
	void add(int pos,int num) {
		for(int i=pos;i;i-=lowbit(i)) {
			val[i]=std::max(val[i],num);
		}
	}
	int qry(int pos) {
		int ret=-1;
		for(int i=pos;i<N;i+=lowbit(i)) {
			ret=std::max(ret,val[i]);
		}
		return ret;
	}
}BIT2;

bool cmp1(int id1,int id2) {
	return y[id1]<y[id2];
}

bool cmp2(int id1,int id2) {
	return ql[id1]>ql[id2];
}

bool cmp3(std::array<int,3> t1,std::array<int,3> t2) {
	return t1[0]>t2[0];
}

int number(int nj) {
	return std::lower_bound(tmp.begin(),tmp.end(),nj)-tmp.begin()+1;
}

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d%d%d",&x[i],&y[i],&w[i]);
		clr[i]=1;
		id[i]=i;
	}
	for(int i=n+1;i<=n+n;i++) {
		scanf("%d%d%d",&x[i],&y[i],&w[i]);
		clr[i]=2;
		id[i]=i;
	}
	std::sort(id+1,id+n+n+1,cmp1);
	divide(1,n+n);
	for(auto par : points) tmp.push_back(par[0]),tmp.push_back(par[1]);
	scanf("%d",&q);
	for(int i=1;i<=q;i++) {
		scanf("%d%d",&ql[i],&qr[i]);
		tmp.push_back(ql[i]); tmp.push_back(qr[i]);
		id[i]=i;
	}
	std::sort(tmp.begin(),tmp.end());
	tmp.erase(std::unique(tmp.begin(),tmp.end()),tmp.end());
	for(auto &par : points) par[0]=number(par[0]),par[1]=number(par[1]);
	for(int i=1;i<=q;i++) ql[i]=number(ql[i]),qr[i]=number(qr[i]);
	memset(ans,-1,sizeof ans);
	////////////////////////////
	std::sort(id+1,id+q+1,cmp2);
	std::sort(points.begin(),points.end(),cmp3);
	for(int i=1,j=0;i<=q;i++) {
		while(j<(int)points.size()&&ql[id[i]]<points[j][0]) {
			BIT1.add(points[j][1],points[j][2]);
			j++;
		}
		ans[id[i]]=std::max(ans[id[i]],BIT1.qry(qr[id[i]]-1));
	}
	////////////////////////////
	for(int i=q,j=(int)points.size()-1;i>=1;i--) {
		while(j>=0&&ql[id[i]]>points[j][0]) {
			BIT2.add(points[j][1],points[j][2]);
			j--;
		}
		ans[id[i]]=std::max(ans[id[i]],BIT2.qry(qr[id[i]]+1));
	}
	////////////////////////////
	for(int i=1;i<=q;i++) {
		printf("%d\n",ans[i]);
	}
	return 0;
}
posted @   Nastia  阅读(134)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示