题意:
给两个长度为n的数组,数字大小不超过1e5,求出它们两两相或的数组c,从小到达排序后支持两种操作:
0 x :查询位置为x的数的当前值
l r:对[l,r]区间的数开方
题解
首先通过fwt得到两两相或的数组。
离散化+线段树版本:
因为区间范围很大,所以先离散化,之后就是写线段树支持区间赋值,区间开方,单点查询的操作。
#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
int n, m;
const int maxn = 4e5 + 50;
ll a[maxn];
ll b[maxn];
void fwt(int len,ll p[],int opt){
for(int i = 2;i <= len;i<<=1){
for(int j = 0,h = i>>1;j < len;j+=i){
for(int k = j;k < j+h;++k){
ll x = p[k],y = p[k+h];
if(opt==1) p[k+h]=(x+y);
else p[k+h]=(y-x); // or
}
}
}return;
}
int len;
void init()
{
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
scanf("%d", &n);
int mx = 0;
for(int i = 1; i <= n; ++i){
int x;
scanf("%d", &x);
mx = max(x, mx);
a[x]++;
}
for(int i = 1;i <= n; ++i){
int x;
scanf("%d", &x);
mx = max(mx, x);
b[x]++;
}
len = 1;while(len <= mx) len<<=1;
fwt(len, a, 1); fwt(len, b, 1);
for(int i = 0; i < len; ++i) a[i] *= b[i];
fwt(len, a, -1);
for(int i = 1; i < len; ++i){
printf("i: %d num: %d\n",i,a[i]);
}
}
ll lz[maxn<<2];
void down(int rt){
if(lz[rt] == -1) return;
lz[rt<<1] = lz[rt<<1|1] = lz[rt];
return;
}
void up(int rt){
if(lz[rt<<1] == lz[rt<<1|1]) lz[rt] = lz[rt<<1];
else lz[rt] = -1;
return;
}
void update(int rt, int l, int r, int L,int R, ll x){
if(L <= l && r <= R){
lz[rt] = x;return;
}
down(rt);
if(L <= mid) update(lson, L, R, x);
if(R > mid) update(rson, L, R, x);
up(rt);
return;
}
void change(int rt, int l, int r, int L, int R){
if(lz[rt] == 1) return;
if(L <= l && r <= R){
if(lz[rt] != -1){
lz[rt] = sqrt(lz[rt]);return;
}
}
down(rt);
if(L <= mid) change(lson, L, R);
if(R > mid) change(rson, L, R);
up(rt);
return;
}
ll query(int rt, int l, int r, int i)
{
if(l <= i && i <= r){
if(lz[rt] != -1) return lz[rt];
}
down(rt);
if( i <= mid) return query(lson, i);
else return query(rson, i);
}
ll cc[maxn*2];
ll num;
struct node{
ll l, r;
int op;//-1为赋值, 0为查询, 1为开根号
ll x;
}e[maxn];
int cnt = 0;
void sol()
{
num = 0;
cnt = 0;
ll res = 0;
for(int i = 0; i < len; ++i){
if(!a[i]) continue;
cc[++num] = res+1;
cc[++num] = res+a[i];
e[cnt].l = res+1;
e[cnt].r = res + a[i];
e[cnt].op = -1;
e[cnt].x = i;
cnt++;
res += a[i];
}
scanf("%d", &m);
while(m--){
ll l, r;
scanf("%lld%lld", &l, &r);
if(l == 0){
e[cnt].op = 0;
e[cnt].x = r;
cnt++;
cc[++num] = r-1;
cc[++num] = r;
}
else{
e[cnt].op = 1;
e[cnt].l = l;
e[cnt].r = r;
cnt++;
cc[++num] = l-1;
cc[++num] = l;
cc[++num] = r;
}
}
sort(cc+1,cc+num+1);
num = unique(cc+1,cc+1+num) - cc-1;
for(int i = 0; i < cnt; ++i){
// cout<<"op:"<<e[i].op<<endl;
if(e[i].op == -1){
int l = lower_bound(cc+1,cc+1+num,e[i].l) - cc;
int r = lower_bound(cc+1,cc+1+num,e[i].r) - cc;
update(1,1,num,l,r,e[i].x);
}
else if(e[i].op == 0){
int id = lower_bound(cc+1,cc+1+num,e[i].x) - cc;
int ans = query(1,1,num,id);
printf("%d\n",ans);
}
else {
int l = lower_bound(cc+1,cc+1+num,e[i].l) - cc;
int r = lower_bound(cc+1,cc+1+num,e[i].r) - cc;
change(1,1,num,l,r);
}
}
}
int main()
{
init();sol();
}
珂朵莉树版本:
fwt之后直接上珂朵莉树,需要注意的是开方操作的同时检查开方完之后整个区间每个结点的值是否相同,如果相同就合并这些结点。
代码又短又好写,赞美柯学!!
#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
int n, m;
const int maxn = 4e5 + 50;
ll a[maxn];
ll b[maxn];
void fwt(int len,ll p[],int opt){
for(int i = 2;i <= len;i<<=1){
for(int j = 0,h = i>>1;j < len;j+=i){
for(int k = j;k < j+h;++k){
ll x = p[k],y = p[k+h];
if(opt==1) p[k+h]=(x+y);
else p[k+h]=(y-x); // or
}
}
}return;
}
int len;
void init()
{
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
scanf("%d", &n);
int mx = 0;
for(int i = 1; i <= n; ++i){
int x;
scanf("%d", &x);
mx = max(x, mx);
a[x]++;
}
for(int i = 1;i <= n; ++i){
int x;
scanf("%d", &x);
mx = max(mx, x);
b[x]++;
}
len = 1;while(len <= mx) len<<=1;
fwt(len, a, 1); fwt(len, b, 1);
for(int i = 0; i < len; ++i) a[i] *= b[i];
fwt(len, a, -1);
}
struct node{
ll l, r;
mutable int val;
node(ll x = 0, ll y = 0, int z = 0):l(x), r(y), val(z){}
bool operator < (const node& x) const {return l < x.l;}
};
set<node> s;
set<node>::iterator split(ll x){
set<node>::iterator it = s.lower_bound(node(x));
if(it!=s.end() && it->l == x) return it;
it--;
ll l = it->l, r = it->r;
int val = it->val;
s.erase(it);
s.insert(node(l, x-1, val));
return s.insert(node(x, r, val)).first;
}
int query(ll l){
set<node> ::iterator it = s.lower_bound(node(l));
if(it!=s.end() && it->l == l) return it->val;
it--;
return it->val;
}
void change(ll l, ll r){
set<node>::iterator rit = split(r+1), lit = split(l);
int ok = 1;
int pre = -1;
while(lit != rit){
lit->val = sqrt(lit->val);
if(pre != -1 && lit->val != pre) ok = 0;
pre = lit->val;
lit++;
}
if(ok){//让时间变松的关键
lit = split(l);
s.erase(lit, rit);
s.insert(node(l, r, pre));
}
}
void sol()
{
ll res = 0;
for(int i = 0; i < len; ++i){
if(!a[i]) continue;
s.insert(node(res+1,res+a[i], i));
res += a[i];
}
int m;
scanf("%d", &m);
while(m--){
ll l ,r;
scanf("%lld%lld", &l, &r);
if(l == 0){
printf("%d\n", query(r));
}
else change(l,r);
}
}
int main()
{
init();sol();
}