题目链接:https://nanti.jisuanke.com/t/40260
题目大意:
给两个长度为n的数组,数字大小不超过1e5,求出它们两两相或的数组c,从小到达排序后支持两种操作:
0 x :查询位置为x的数的当前值
l r:对[l,r]区间的数开方
思路:我们通过fwt得到c数组。c[i]:i的个数。区间开方肯定用线段树维护。问题是区间长度为n * n。我们考虑对于操作:
1 10000000000
0 5
我们真的要建长度为10000000000的线段树吗?其实我们就用到1, 5, 10000000000。3个点。我们肯定考虑离散化。在操作中出现的点保留。开一个2*n的线段树就可以了。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL N;
struct FWT_{
void FWT_or(LL *a,LL opt) {
for(LL i=1; i<N; i<<=1)
for(LL p=i<<1,j=0; j<N; j+=p)
for(LL 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];
}
void ans_or(LL cnt1[], LL cnt2[]){
FWT_or(cnt1, 1); FWT_or(cnt2, 1);
for(LL i = 0; i < N; ++i) cnt1[i] = cnt1[i]*cnt2[i];
FWT_or(cnt1, -1);
// LL s=0;
// for(LL i=0; i<N; i++){
// s+=cnt1[i];
// printf("%-3lld ", s);
// }
// printf("\n");
// for(LL i=0; i<N; i++){
// printf("%-3lld ", i);
// }
// printf("\n");
}
}fwt;
struct SegTree {
LL T[200005<<2], sum[200005<<2];
//clear_Tree () { memset(T,0,sizeof(T)); memset(sum,0,sizeof(sum)); }
inline void pushup(LL o) { T[o]=max(T[o<<1],T[o<<1|1]); sum[o]=sum[o<<1]+sum[o<<1|1]; }
inline void up_data(LL o,LL l,LL r,LL x, LL y){
if(l==r){
T[o]=sum[o]=y;
return ;
}
LL mid=l+r>>1;
if(x<=mid) up_data(o<<1,l,mid,x, y);
else up_data(o<<1|1,mid+1,r,x, y);
pushup(o);
}
inline void add(LL o,LL l,LL r, LL ql, LL qr){//ql qr开方
if(T[o]==1) return ;
if(l==r){
T[o]=sqrt(T[o]);
sum[o]=T[o];
return ;
}
LL mid=l+r>>1;
if(qr<=mid) add(o<<1,l,mid,ql,qr);
else if(ql>mid) add(o<<1|1,mid+1,r,ql,qr);
else add(o<<1,l,mid,ql,mid), add(o<<1|1,mid+1,r,mid+1,qr);
pushup(o);
}
inline LL query(LL o,LL l,LL r,LL x){//查询a[x]
if(T[o]==1) return 1;
if(l==r) return T[o];
LL mid=l+r>>1;
if(x<=mid) return query(o<<1,l,mid,x);
else return query(o<<1|1,mid+1,r,x);
}
}T;
struct Node{
LL x, y;
LL p;//0查询 1修改
}q[200005];
LL a[200005], b[200005], cnt1[200005], cnt2[200005];
LL c[200005], tot=0;
int main() {
LL n; scanf("%lld", &n);
LL mx=0;
for(LL i=0; i<n; i++){
scanf("%lld", &a[i]);
cnt1[a[i]]++;
mx=max(a[i], mx);
}
for(LL i=0; i<n; i++){
scanf("%lld", &b[i]);
cnt2[b[i]]++;
mx=max(b[i], mx);
}
N = 1;while(N <= mx) N<<=1;
fwt.ans_or(cnt1, cnt2);//fwt
LL Q; scanf("%lld", &Q);
for(LL i=1; i<=Q; i++){//保存操作
LL x, y; scanf("%lld%lld", &x, &y);
if(x==0){
q[i].p=0, q[i].x=y;
c[++tot]=y;
}
else{
q[i].p=1, q[i].x=x, q[i].y=y;
c[++tot]=x; c[++tot]=y;
}
}
sort(c+1, c+tot+1);
LL cnt=unique(c+1, c+tot+1)-c-1;
for(LL i=1; i<=Q; i++){//离散化
if(q[i].p==0){
q[i].x=lower_bound(c+1, c+cnt+1, q[i].x)-c;
}
else{
q[i].x=lower_bound(c+1, c+cnt+1, q[i].x)-c;
q[i].y=lower_bound(c+1, c+cnt+1, q[i].y)-c;
}
}
LL s=0, pos=0;
for(LL i=1; i<=cnt; i++){
while(s<c[i]){
s+=cnt1[++pos];
}
T.up_data(1, 1, cnt, i, pos);//把需要的点加入线段树
}
for(LL i=1; i<=Q; i++){
if(q[i].p==0){
printf("%lld\n", T.query(1, 1, cnt, q[i].x));
}
else{
T.add(1, 1, cnt, q[i].x, q[i].y);
}
}
return 0;
}

京公网安备 11010502036488号