HDU7059-Counting Stars 线段树 (区间加最低位置,区间减最高位)
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU7059-Counting Stars 线段树 (区间加最低位置,区间减最高位)相关的知识,希望对你有一定的参考价值。
题意:
一个序列,三种操作
1.查询序列l,r之间的和
2.给l,r之间每个数加上自己二进制最高位
3.给l,r之间每个数减去自己二进制的最低位置。
题解:
我们把一个数分解成二进制的状态进行思考,设cnt为数x当前二进制状态下不为0的位数有多少,我们发现对于两个修改操作,你无论怎么修改,cnt都不会增加,考虑1e9最多有30位不为1的数,你每进行一次操作3,这个数的cnt就会-1,那么每个数最多可以进行30次操作三,多余的操作三没有什么效果。
我们可以把一个数分成(最高位+其他位)来进行维护。
那么对于操作3来讲,我们直接去暴力操作即可(暴力修改每个叶子结点,当一段区间最高位+次高位等于0时,就不需要递归下去了)
如果其他位不为0,那么直接用其他位-lowbit(其他位),如果为0,那么直接把最高位置为0即可。
操作2进行正常的区间修改。
操作三我们直接对最高位乘2(区间修改),其他位不变。
代码:
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>
#define endl '\\n'
using namespace std;
const int maxn=1e5+10;
int a[maxn];
inline char nc()
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread (buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
inline void read(int &sum)
char ch = nc();
int tf = 0;
sum = 0;
while((ch < '0' || ch > '9') && (ch != '-')) ch = nc();
tf = ((ch == '-') && (ch = nc()));
while(ch >= '0' && ch <= '9') sum = sum * 10+ (ch - 48), ch = nc();
(tf) && (sum =- sum);
inline void write(int x)
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
const int mod=998244353;
long long maxsum[maxn<<2],lowsum[maxn<<2];
int bit[maxn+100],lazy[maxn<<2],b[maxn<<2];
bool maxsumbit[maxn<<2];
void push_up(int node)
lowsum[node]=(lowsum[node<<1]+lowsum[node<<1|1])%mod;
maxsum[node]=(maxsum[node<<1]+maxsum[node<<1|1])%mod;
if(!maxsumbit[node<<1]&&!maxsumbit[node<<1|1]) maxsumbit[node]=false;
else maxsumbit[node]=true;
void push_down(int node)
if(lazy[node])
lazy[node<<1]+=lazy[node];
lazy[node<<1|1]+=lazy[node];
maxsum[node<<1]=(maxsum[node<<1]*bit[lazy[node]])%mod;
maxsum[node<<1|1]=(maxsum[node<<1|1]*bit[lazy[node]])%mod;
lazy[node]=0;
void build(int node,int start,int ends)
lazy[node]=0;
if(start==ends)
if(b[start]==-1) maxsumbit[node]=false;
else maxsumbit[node]=true;
lowsum[node]=a[start]%mod;
if(b[start]!=-1) maxsum[node]=bit[b[start]];
else maxsum[node]=0;
return ;
int mid=(start+ends)>>1;
build(node<<1,start,mid);
build(node<<1|1,mid+1,ends);
push_up(node);
void update_pos(int node,int start,int ends,int l,int r)
if(!maxsumbit[node]) return ;
if(start==ends)
if(lowsum[node]==0)
maxsum[node]=0;
maxsumbit[node]=false;
else lowsum[node]=(lowsum[node]-(lowsum[node]&(-lowsum[node]))+mod)%mod;
return ;
push_down(node);
int mid=(start+ends)>>1;
if(l<=mid) update_pos(node<<1,start,mid,l,r);
if(mid<r) update_pos(node<<1|1,mid+1,ends,l,r);
push_up(node);
void update_sec(int node,int start,int ends,int l,int r)
if(!maxsumbit[node]) return;
if(l<=start&&ends<=r)
maxsum[node]=(maxsum[node]*2)%mod;
lazy[node]++;
return ;
push_down(node);
int mid=(start+ends)>>1;
if(l<=mid) update_sec(node<<1,start,mid,l,r);
if(mid<r) update_sec(node<<1|1,mid+1,ends,l,r);
push_up(node);
long long query(int node,int start,int ends,int l,int r)
if(l<=start&&ends<=r)
return (lowsum[node]+maxsum[node])%mod;
int mid=(start+ends)>>1;
push_down(node);
long long res=0;
if(l<=mid) res=(res+query(node<<1,start,mid,l,r));
if(mid<r) res=(res+query(node<<1|1,mid+1,ends,l,r));
return res;
signed main()
bit[0]=1;
for(int i=1;i<=100100;i++)
bit[i]=(bit[i-1]*2)%mod;
int t;
read(t);
while(t--)
int n;
read(n);
for(int i=1;i<=n;i++)
read(a[i]);
b[i]=-1;
for(int k=31;k>=0;k--)
if((a[i]>>k&1)==1)
b[i]=k;
break;
if(b[i]!=-1) a[i]-=bit[b[i]];
build(1,1,n);
int q;
read(q);
while(q--)
int opt,x,y;
read(opt);read(x);read(y);
if(opt==1)
int ans=(query(1,1,n,x,y)%mod+mod)%mod;
write(ans);
putchar('\\n');
else if(opt==2) //sub
update_pos(1,1,n,x,y);
else
update_sec(1,1,n,x,y);
以上是关于HDU7059-Counting Stars 线段树 (区间加最低位置,区间减最高位)的主要内容,如果未能解决你的问题,请参考以下文章
HDU7059-Counting Stars 线段树 (区间加最低位置,区间减最高位)