COGS. 2638. 數(shù)列操作(吉司機(jī)線(xiàn)段樹(shù))
題面鏈接
(COGS什么時(shí)候沒(méi)的... 記得還能下數(shù)據(jù)挺良心的)
\(Description\)
給定長(zhǎng)為\(n\)數(shù)列,需支持區(qū)間\(\text{or}\)、\(\text{and}\)、求區(qū)間最大值。
\(n,m\leq10^5\)。
\(Solution\)
考慮更簡(jiǎn)單的情況:所有操作區(qū)間為\([1,n]\)。
如果\(\text{and},\text{or}\)的值隨機(jī),那么幾次之后所有數(shù)就全相同了。
如果不隨機(jī),至少在\(\text{and}\)中為\(1\)、\(\text{or}\)中為\(0\)的這些位都全相同了。
對(duì)于不同的二進(jìn)制位直接對(duì)所有數(shù)求最大值。
(上面的討論其實(shí)沒(méi)什么用,不過(guò)jls這么講的)
下面可能寫(xiě)錯(cuò)了 我有空再改改 直接看代碼吧
若區(qū)間不為\([1,n]\),維護(hù)一個(gè)\(same\)表示某區(qū)間所有數(shù)都相同的那些位,以及區(qū)間最大值\(mx\)。
若當(dāng)前修改 \(\text{and}\)中為\(1\)的位 或 \(\text{or}\)中為\(0\)的位 是當(dāng)前節(jié)點(diǎn)\(x\)的\(same[x]\)的子集,就可以直接整體修改,而且就是對(duì)該區(qū)間所有\(mx\)加上 \(改后的值-mx[x]\)。直接打區(qū)間加減的\(tag\)修改\(mx\)即可。
所以,直接用吉司機(jī)線(xiàn)段樹(shù)的寫(xiě)法,記\(\text{and}\)中為\(1\)的位 或 \(\text{or}\)中為\(0\)的位集為\(s\),若當(dāng)前區(qū)間是修改區(qū)間的子區(qū)間 且 s&same[x]=s,則\(O(1)\)進(jìn)行區(qū)間加/減;否則遞歸子區(qū)間。
查詢(xún)時(shí)可以直接查區(qū)間\(mx\)。
復(fù)雜度(??沒(méi)好好聽(tīng)jls講),應(yīng)該也是\(O(n\log^2n)\)常表現(xiàn)為\(O(n\log n)\)的?
PS:關(guān)于暴力寫(xiě)法,涉及到兩種\(tag\),需要先定義標(biāo)記的優(yōu)先級(jí)(先下放哪個(gè))。優(yōu)先級(jí)低的標(biāo)記修改直接改,優(yōu)先級(jí)高的標(biāo)記修改時(shí),需要用優(yōu)先級(jí)高(先下放)的修改一下優(yōu)先級(jí)低的(后下放)的。
如區(qū)間加、乘,若先下放乘再加,則加操作時(shí)直接加,乘操作時(shí)加標(biāo)記需要乘一下。
(普及組知識(shí)讓我再?gòu)?fù)習(xí)一下)
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=2e5+6,INF=2147483647;
int read();
struct Segment_Tree
{
#define S N<<2
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,ls
#define rson m+1,r,rs
int same[S],mx[S],tag[S];
#undef S
#define Upd(rt,v) mx[rt]+=v, tag[rt]+=v
#define Update(rt) mx[rt]=std::max(mx[ls],mx[rs]), same[rt]=same[ls]&same[rs]&(~(mx[ls]^mx[rs]))
inline void PushDown(int rt)
{
if(tag[rt]) Upd(ls,tag[rt]), Upd(rs,tag[rt]), tag[rt]=0;
}
void Build(int l,int r,int rt)
{
if(l==r) {same[rt]=INF, mx[rt]=read(); return;}
int m=l+r>>1;
Build(lson), Build(rson), Update(rt);
}
void Modify_AND(int l,int r,int rt,int L,int R,int v)
{
if(l==r) {mx[rt]&=v; return;}
if(L<=l && r<=R && (((~v)&INF)&same[rt])==((~v)&INF))
{
int t=(mx[rt]&v)-mx[rt];
Upd(rt,t); return;
}
PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify_AND(lson,L,R,v);
if(m<R) Modify_AND(rson,L,R,v);
Update(rt);
}
void Modify_OR(int l,int r,int rt,int L,int R,int v)
{
if(l==r) {mx[rt]|=v; return;}
if(L<=l && r<=R && (v&same[rt])==v)
{
int t=(mx[rt]|v)-mx[rt];
Upd(rt,t); return;
}
PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify_OR(lson,L,R,v);
if(m<R) Modify_OR(rson,L,R,v);
Update(rt);
}
int Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return mx[rt];
PushDown(rt);
int m=l+r>>1;
if(L<=m)
if(m<R) return std::max(Query(lson,L,R),Query(rson,L,R));
else return Query(lson,L,R);
return Query(rson,L,R);
}
}T;
inline int read()
{
int now=0,f=1; char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int n=read(),Q=read();
#define S 1,n,1
T.Build(S);
for(int opt,L,R,x; Q--; )
{
opt=read(), L=read(), R=read();
switch(opt)
{
case 1: x=read(), T.Modify_AND(S,L,R,x); break;
case 2: x=read(), T.Modify_OR(S,L,R,x); break;
case 3: printf("%d\n",T.Query(S,L,R)); break;
}
}
return 0;
}
別來(lái)無(wú)恙 你在心上
------------------------------------------------------------------------------------------------------------------------

浙公網(wǎng)安備 33010602011771號(hào)