[CF1004F] Sonya and Bitwise OR

\(\text{Problem}:\)Sonya and Bitwise OR

\(\text{Solution}:\)

分析一下 OR 的性质。对于左端点 \(l\) 固定的区间,其前缀至多只会有 \(\lceil \log_{2}V\rceil\) 个不同的取值,且每种取值都是连续的。当右端点固定时也是同理。

那么对于每个区间 \([l,r]\),维护其前缀与后缀每种不同取值的起始位置与长度。合并时只需枚举左儿子和右儿子的不同取值,在 \(O(20^{2})\) 的复杂度内暴力求出答案,而更新其前缀与后缀的信息也非常容易。

总时间复杂度 \(O(n\log n\log^{2} V)\)。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=100010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,X,a[N];
#define lc (x<<1)
#define rc (x<<1|1)
struct Node { vpi pre,nxt; long long sum; inline Node() { sum=0; } }w[N<<2],zero;
inline Node Merge(Node x,Node y)
{
	Node res;
	res.sum=x.sum+y.sum;
	for(auto i:x.nxt)
	{
		for(auto j:y.pre)
		{
			if((i.fi|j.fi)>=X) res.sum+=1ll*i.se*j.se;
		}
	}
	res.pre=x.pre;
	for(auto i:y.pre)
	{
		if((i.fi|res.pre.back().fi)==res.pre.back().fi) res.pre.back().se+=i.se;
		else res.pre.eb(mk((res.pre.back().fi|i.fi),i.se));
	}
	res.nxt=y.nxt;
	for(auto i:x.nxt)
	{
		if((i.fi|res.nxt.back().fi)==res.nxt.back().fi) res.nxt.back().se+=i.se;
		else res.nxt.eb(mk((res.nxt.back().fi|i.fi),i.se));
	}
	return res;
}
void Build(int x,int l,int r)
{
	if(l==r)
	{
		w[x].pre.eb(mk(a[l],1));
		w[x].nxt.eb(mk(a[l],1));
		w[x].sum=(a[l]>=X);
		return;
	}
	int mid=(l+r)/2;
	Build(lc,l,mid);
	Build(rc,mid+1,r);
	w[x]=Merge(w[lc],w[rc]);
}
void UpDate(int pos,int l,int r,int x,int k)
{
	if(l==r)
	{
		w[x].pre.clear(), w[x].nxt.clear();
		w[x].pre.eb(mk(k,1)), w[x].nxt.eb(mk(k,1));
		w[x].sum=(k>=X);
		return;
	}
	int mid=(l+r)/2;
	if(pos<=mid) UpDate(pos,l,mid,lc,k);
	else UpDate(pos,mid+1,r,rc,k);
	w[x]=Merge(w[lc],w[rc]);
}
Node Ask(int u,int v,int l,int r,int x)
{
	if(l>v||r<u) return zero;
	if(l>=u&&r<=v) return w[x];
	int mid=(l+r)/2;
	if(u>mid) return Ask(u,v,mid+1,r,rc);
	if(v<=mid) return Ask(u,v,l,mid,lc);
	return Merge(Ask(u,mid,l,mid,lc),Ask(mid+1,v,mid+1,r,rc));
}
#undef lc
#undef rc
signed main()
{
	n=read(), m=read(), X=read();
	for(ri int i=1;i<=n;i++) a[i]=read();
	Build(1,1,n);
	for(ri int i=1;i<=m;i++)
	{
		int opt=read();
		if(opt==1)
		{
			int x,y;
			x=read(), y=read();
			UpDate(x,1,n,1,y);
		}
		else
		{
			int l,r;
			l=read(), r=read();
			printf("%lld\n",Ask(l,r,1,n,1).sum);
		}
	}
	return 0;
}
上一篇:一个复制文件的Shell脚本


下一篇:重新加载网卡默认驱动