XX Open Cup, Grand Prix of Tokyo D,L
D
二分max值为L,判定能否使用\(\leq L\)的数构造出答案。
暂时不管L的限制。此时如果我们有一组解,表示为\(c_{0},c_{1},...,c_{60}\),其中\(c_{i}\)是有多少个数在第\(i\)位为\(1\)。那么我们可以将\(c_{i}\)减\(2\),\(c_{i-1}\)加\(4\);或者\(c_{i}\)减\(4\),\(c_{i+1}\)加\(2\),构造出所有合法解。(为什么不是\(c_{i}\)减\(1\),\(c_{i-1}\)加\(2\)呢?因为我们不仅要让\(sum\)不变,还要让\(xor\)不变,所以加减的数必然是偶数)
那么我们如何构造\(c\)?设\(x_{i}\)为异或和\(X\)的第\(i\)位,\(s_{i}\)为和\(S\)的第\(i\)位。那么\(x_{i}=1\)意味着\(c_{i}\)为奇数,也就是\(c_{i}\geq 1\),那么我们不妨将\(X\)减去\(S\),此时每个数都出现了偶数次,那么我们将其除以二,我们设这样操作后的数为\(Y\)(\(Y=(S-X)/2\)),第\(i\)位为\(y_{i}\)。不难构造出\(c_{i}=2y_{i}+x_{i}\)。
L
我们对第一个限制分治,也就是,我们对\(y\)坐标从小到大排序,每次分成左右两个区间,并且记录出现在左侧的红点和出现在右侧的蓝点,那么我们就想让红点和蓝点匹配。
直接暴力匹配是\(O(n^2)\)的(当然也体现不出分治的意义),但是这里有一个结论:最大权值的匹配必然是有一个颜色的点的权值最大。也就是,只能是左侧红点中\(w\)最大的和右侧所有蓝点匹配;或者右侧蓝点\(w\)最大的和左侧红点匹配。
证明很简单——假设当前我们的询问为\([L,R]\),当前分治的区间为\([lef,rig]\),左半部分为\([lef,mid]\),右半部分为\([mid+1,rig]\)。若\(L\leq lef\leq rig\leq R\),那么区间内所有点对都满足条件\(2\)。否则若\(lef\leq L\leq mid\leq R\leq rig\),则左侧最大值和右侧最大值会落到\([lef,L-1],[L,mid],[mid+1,R],[R+1,rig]\)这四个区间的两个中,那么根据抽屉原理,我们取\(1,4\)和\(2,3\)段时,必然会出现包含左侧最大值或右侧最大值的段。否则就是相交的情况,其实就是将四段变成三段或更少,也是满足条件的。
那么这样点对数就降到\(O(n\log n)\)。我们处理出这些点对。回答询问可以让询问离线,将询问和点对按左节点从小往大\从大往小排序,用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;
}
浙公网安备 33010602011771号