Codeforces 1004F Sonya and Bitwise OR (线段树)

题目链接

https://codeforces.com/contest/1004/problem/F

题解

这种水题都不会做了怎么。。

考虑一个序列的前缀 \(\text{or}\) 值只会变化 \(O(\log W)\) 次,于是线段树维护每个区间的前缀和后缀 \(\text{or}\) 值即可。

时间复杂度 \(O(n\log n\log W)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define iter iterator
#define riter reversed_iterator
#define y1 Lorem_ipsum_dolor
#define pii pair<int,int>
using namespace std;

inline int read()
{
	int x = 0,f = 1; char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) {if(ch==‘-‘) f = -1;}
	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
	return x*f;
}

const int mxN = 1e5;
const int lgA = 20;
int a[mxN+3];
int n,q,X;

struct Data
{
	pii pre[lgA+3],suf[lgA+3]; llong sum; int pren,sufn;
} sgt[mxN*4+3];
Data operator +(Data ls,Data rs)
{
	Data ret; ret.sum = ls.sum+rs.sum; ret.pren = ret.sufn = 0;
	llong cur = 0ll;
	for(int i=1,j=rs.pren+1; i<=ls.sufn; i++)
	{
		while(j>1&&(rs.pre[j-1].first|ls.suf[i].first)>=X) {j--; cur += rs.pre[j].second;}
		ret.sum += 1ll*ls.suf[i].second*cur;
	}
	for(int i=1; i<ls.pren; i++) {ret.pre[++ret.pren] = ls.pre[i];}
	pii tmp = ls.pre[ls.pren];
	for(int i=1; i<=rs.pren; i++)
	{
		if((tmp.first|rs.pre[i].first)==tmp.first) {tmp.second += rs.pre[i].second;}
		else
		{
			ret.pre[++ret.pren] = tmp;
			tmp.first |= rs.pre[i].first; tmp.second = rs.pre[i].second;
		}
	}
	ret.pre[++ret.pren] = tmp;
	for(int i=1; i<rs.sufn; i++) {ret.suf[++ret.sufn] = rs.suf[i];}
	tmp = rs.suf[rs.sufn];
	for(int i=1; i<=ls.sufn; i++)
	{
		if((tmp.first|ls.suf[i].first)==tmp.first) {tmp.second += ls.suf[i].second;}
		else
		{
			ret.suf[++ret.sufn] = tmp;
			tmp.first |= ls.suf[i].first; tmp.second = ls.suf[i].second;
		}
	}
	ret.suf[++ret.sufn] = tmp;
	return ret;
}
void build(int u,int le,int ri)
{
	if(le==ri) {sgt[u].pren = sgt[u].sufn = 1,sgt[u].pre[1] = sgt[u].suf[1] = mkpr(a[le],1),sgt[u].sum = a[le]>=X?1:0; return;}
	int mid = (le+ri)>>1;
	build(u<<1,le,mid); build(u<<1|1,mid+1,ri);
	sgt[u] = sgt[u<<1]+sgt[u<<1|1];
}
void modify(int u,int le,int ri,int pos,int x)
{
	if(le==ri) {sgt[u].pre[1] = sgt[u].suf[1] = mkpr(x,1),sgt[u].sum = x>=X?1:0; return;}
	int mid = (le+ri)>>1;
	if(pos<=mid) modify(u<<1,le,mid,pos,x); else modify(u<<1|1,mid+1,ri,pos,x);
	sgt[u] = sgt[u<<1]+sgt[u<<1|1];
}
Data query(int u,int le,int ri,int lb,int rb)
{
	if(le>=lb&&ri<=rb) {return sgt[u];}
	int mid = (le+ri)>>1;
	if(rb<=mid) {return query(u<<1,le,mid,lb,rb);}
	else if(lb>mid) {return query(u<<1|1,mid+1,ri,lb,rb);}
	else {return query(u<<1,le,mid,lb,mid)+query(u<<1|1,mid+1,ri,mid+1,rb);}
}

int main()
{
	n = read(),q = read(),X = read();
	for(int i=1; i<=n; i++) a[i] = read();
	build(1,1,n);
	while(q--)
	{
		int opt = read();
		if(opt==1)
		{
			int u = read(),x = read();
			modify(1,1,n,u,x);
		}
		else
		{
			int l = read(),r = read();
			Data ans = query(1,1,n,l,r);
			printf("%I64d\n",ans.sum);
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/suncongbo/p/12628829.html

时间: 2024-10-19 22:54:38

Codeforces 1004F Sonya and Bitwise OR (线段树)的相关文章

codeforces 444 C. DZY Loves Colors(线段树)

题目大意: 1 l r x操作 讲 [l,r]上的节点涂成x颜色,并且每个节点的值都加上 |y-x| y为涂之前的颜色 2 l r  操作,求出[l,r]上的和. 思路分析: 如果一个区间为相同的颜色.那么我们才可以合并操作. 所以我们之前找相同的区间就好. 但是问题是如何合并操作. 那么我们定义一个val  表示这个区间每个位置上应该加上的值. pushdown 的时候这个值是可以相加的. #include <cstdio> #include <iostream> #includ

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

Codeforces 444C DZY Loves Colors 水线段树

题目链接:点击打开链接 水.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set> #include <vector> #include <map> using namespace std; #define ll long long #defi

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

codeforces Beta Round #19 D. Point (线段树 + set)

题目大意: 对平面上的点进行操作. add x y 在 (x,y )上加一个点. remove x y 移除 (x,y)上的点. find x y 求出在(x,y)右上角离他最近的点,优先级是靠左,靠下. 思路分析: find 操作 比较麻烦. 要保证x大的同时还要确保x最小,而且该x上还要有点. 这样要找大的时候要小的,就是在线段树上选择性的进入左子树还是右子树. 所以核心就是,用set维护叶子节点. 然后查找的时候去叶子节点找,如果这个叶子节点有蛮子的 x y  就输出,否则回溯去另外一个子

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

codeforces 339C Xenia and Bit Operations(线段树水题)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Xenia and Bit Operations Xenia the beginner programmer has a sequence a, consisting of 2n non-negative integers: a1, a2, ..., a2n. Xenia is currently studying bit operations. To better unders

Codeforces Gym 100513F F. Ilya Muromets 线段树

F. Ilya Muromets Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513/problem/F Description I Ilya Muromets is a legendary bogatyr. Right now he is struggling against Zmej Gorynych, a dragon with n heads numbered from 1 to nf

codeforces 573B B. Bear and Blocks(线段树+dp)

题目链接: codeforces 573B 题目大意: 给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块. 题目分析: 首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式: hi=min(hi?1,hi?1,hi+1) 每次操作都满足如下的递推式,我们递推一下得到第k次操作第i的塔的高度: hi=max(0,minj=0i{min(hi?j?(k?j),hi+j?(k?j)}?hi=max(0,minj=0i{min(hi?j+j?k,hi+j+j