题目链接
思路:先贴一个fwt模板。
由于数组是一些 相同的元素段 组成的。所以用一个set维护一下,每个段的信息。
然后查询直接set上二分。
修改操作是修改一些连续段,把每个段的值都更新一下,为了防止复杂度退化,必须要合并值相同的相邻段。就可以了。剩下的就是set上模拟模拟即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
int N;
void FWT_or(LL *a, int opt){
for (int i = 1; i < N; i <<= 1)
for (int p = i << 1, j = 0; j < N; j += p)
for (int k = 0; k < i; ++k)
if (opt == 1)a[i + j + k] = (a[j + k] + a[i + j + k]) ;
else a[i + j + k] = (a[i + j + k]- a[j + k]);
}
LL a[1<<18],b[1<<18];
int n;
set<pair<LL,pair<LL,int>>>s;
LL l1,l2;
int l3;
vector<pair<LL,pair<LL,int>>>ad,de;
int add(LL x,LL y,int z){
if(z==l3){
l1=x;
return 1;
}
if(l3!=-1){
ad.pb(mp(l1,mp(l2,l3)));
l3=-1;
}
l1=x;l2=y;l3=z;
return 0;
}
void LA(){
for(auto k:de){
s.erase(k);
}
}
void LB(){
for(auto k:ad){
s.insert(k);
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
a[x]++;
}
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
b[x]++;
}
int l=0;
while((1<<l)<100000)l++;
n=N=1<<l;
FWT_or(a,1);
FWT_or(b,1);
for(int i=1;i<n;i++)a[i]*=b[i];
FWT_or(a,-1);
LL tot=0;
for(int i=1;i<n;i++){
if(a[i]){
s.insert(mp(tot+a[i],mp(tot,i)));
}
tot+=a[i];
}
int m;scanf("%d",&m);
for(int i=1;i<=m;i++){
LL l,r;
scanf("%lld%lld",&l,&r);
if(!l){
auto g=s.lower_bound(mp(r,mp(0,0)));
printf("%d\n",(*g).se.se);
}else{
ad.clear();de.clear();
auto g=s.lower_bound(mp(l,mp(0, 0)));
l3=-1;l2=0,l1=0;
pair<LL,pair<LL,int>>x=*g;
if(l-1-x.se.fi>0){
add(l-1,x.se.fi,x.se.se);
add(min(r,x.fi),l,sqrt(x.se.se));
if(r<x.fi){
add(x.fi,r,x.se.se);
}
}else {
add(min(r,x.fi),x.se.fi,sqrt(x.se.se));
if(r<x.fi){
add(x.fi,r,x.se.se);
}
}
de.pb(x);
++g;
while(g!=s.end() &&(*g).fi<=r){
add(((*g).fi),(*g).se.fi,sqrt((*g).se.se));
de.pb(*g);
g++;
}
if(g!=s.end()){
if((*g).se.fi<r){
add(r,(*g).se.fi,sqrt((*g).se.se));
add((*g).fi ,r ,(*g).se.se);
de.pb(*g);
}
}
if(l3!=-1){
ad.pb(mp(l1,mp(l2,l3)));
}
LA();
LB();
}
}
return 0;
}
// 6 10 11 20 6 20 21 25