[cogs2638]数列操作ψ(双标记线段树)
生活随笔
收集整理的這篇文章主要介紹了
[cogs2638]数列操作ψ(双标记线段树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目大意:給定一個數列a,你需要支持的操作:區間and,區間or,詢問區間最大值
解題關鍵:
1、雙標記線段樹,注意優先級(超時)
當涉及多重標記時,定義出標記的優先級,修改操作時用優先級高(先下放)的修正優先級低(后下放)的來保證標記的正確性。
同時維護了區間and,區間or
https://blog.csdn.net/PhantomAgony/article/details/78810369
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define MAXN 100010
#define INF 0x7fffffff
#define lc rt<<1
#define rc rt<<1|1
namespace IO{
char buf[<<],*fs,*ft;
inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;}
inline int qr(){
int x=,rev=,ch=gc();
while(ch<''||ch>''){if(ch=='-')rev=;ch=gc();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=gc();}
return rev?-x:x;}
}using namespace IO;
using namespace std;
int N,Q,tago[MAXN<<],taga[MAXN<<],vo[MAXN<<],va[MAXN<<],ma[MAXN<<],a[MAXN];
inline void Up(int rt){
vo[rt]=vo[lc]|vo[rc];va[rt]=va[lc]&va[rc];
ma[rt]=max(ma[lc],ma[rc]);
} inline void PutAnd(int rt,int x){//雙標記模板題
taga[rt]&=x;tago[rt]&=x;
ma[rt]&=x;vo[rt]&=x;va[rt]&=x;
}
inline void PutOr(int rt,int x){
tago[rt]|=x;
ma[rt]|=x;vo[rt]|=x;va[rt]|=x;
}
inline void Down(int rt){
if(taga[rt]^INF){
PutAnd(lc,taga[rt]);
PutAnd(rc,taga[rt]);
taga[rt]=INF;
}
if(tago[rt]){
PutOr(lc,tago[rt]);
PutOr(rc,tago[rt]);
tago[rt]=;
}
} void Build(int l,int r,int rt){
taga[rt]=INF;
if(l==r){va[rt]=vo[rt]=ma[rt]=a[l];return;}
int mid=(l+r)>>;
Build(l,mid,lc);
Build(mid+,r,rc);
Up(rt);
}
void Modify(int L,int R,int l,int r,int rt,int x,bool flag){
if(L<=l&&R>=r){
if(flag){//區間&
if(((x^INF)&(va[rt]|(vo[rt]^INF)))==(x^INF)){//都為1或都為0
PutAnd(rt,x);
return;
}
}
else{//區間|
if((x&(va[rt]|(vo[rt]^INF)))==x){
PutOr(rt,x);
return;
}
}
}
Down(rt);
int mid=l+r>>;
if(L<=mid)Modify(L,R,l,mid,lc,x,flag);
if(R>mid)Modify(L,R,mid+,r,rc,x,flag);
Up(rt);
}
int Query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r)return ma[rt];
int mid=(l+r)>>,ret=;
Down(rt);
if(L<=mid)ret=Query(L,R,l,mid,lc);
if(R>mid)ret=max(ret,Query(L,R,mid+,r,rc));
return ret;
}
int op,x,y,z;
int main(){
freopen("series_wei.in","r",stdin);
freopen("series_wei.out","w",stdout);
N=qr();Q=qr();
for(int i=;i<=N;i++)a[i]=qr();
Build(,N,);
while(Q--){
op=qr();x=qr();y=qr();
if(op==)z=qr(),Modify(x,y,,N,,z,);
else if(op==)z=qr(),Modify(x,y,,N,,z,);
else printf("%d\n",Query(x,y,,N,));
}
return ;
}
2、一個same維護區間內相同的位
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = ;
const int bas = 0x7fffffff;
int T[maxn<<],lazy[maxn<<],sam[maxn<<];
int a[maxn];
inline void update(int rt){
T[rt]=max(T[rt<<],T[rt<<|]);
sam[rt]=(sam[rt<<]&sam[rt<<|])&(~(T[rt<<]^T[rt<<|]));
} inline void pushdown(int rt){
if(!lazy[rt]) return ;
T[rt<<]+=lazy[rt];lazy[rt<<]+=lazy[rt];
T[rt<<|]+=lazy[rt];lazy[rt<<|]+=lazy[rt];
lazy[rt]=;
} void build(int rt,int l,int r){
if(l==r){
T[rt]=a[l];
sam[rt]=bas;//全1
return;
}
int mid=l+r>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
update(rt);
}
int L,R,val,tmp; inline bool check_a(int rt){
tmp=(val^bas);
return (tmp&sam[rt])==tmp;
} void modify_a(int rt,int l,int r){
if(L<=l&&r<=R&&check_a(rt)){
tmp=(T[rt]&val)-T[rt];
lazy[rt]+=tmp;
T[rt]+=tmp;
return;
}
pushdown(rt);
int mid=l+r>>;
if(L<=mid) modify_a(rt<<,l,mid);
if(R>mid) modify_a(rt<<|,mid+,r);
update(rt);
}
void modify_o(int rt,int l,int r){
if(L<=l&&r<=R&&(sam[rt]&val)==val){
tmp=(T[rt]|val)-T[rt];
lazy[rt]+=tmp;
T[rt]+=tmp;
return;
}
int mid=l+r>>;
pushdown(rt);
if(L<=mid) modify_o(rt<<,l,mid);
if(R>mid) modify_o(rt<<|,mid+,r);
update(rt);
} int query(int rt,int l,int r){
if(L<=l&&r<=R) return T[rt];
pushdown(rt);
int mid=l+r>>,res=;
if(L<=mid) res=max(res,query(rt<<,l,mid));
if(R>mid) res=max(res,query(rt<<|,mid+,r));
return res;
}
int main(){
freopen("series_wei.in","r",stdin);
freopen("series_wei.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",a+i);
build(,,n);
int opt;
while(m--){
scanf("%d%d%d",&opt,&L,&R);
if(opt == ) scanf("%d",&val),modify_a(,,n);
else if(opt == ) scanf("%d",&val),modify_o(,,n);
else printf("%d\n",query(,,n));
}
return ;
}
總結
以上是生活随笔為你收集整理的[cogs2638]数列操作ψ(双标记线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P5020 [NOIP2018 提高组]
- 下一篇: NOIp2020游记