1. 程式人生 > >序列操作 - 線段樹

序列操作 - 線段樹

題目大意:你要維護一個長度為n的序列,進行操作。
對於這個序列,233之類的數不能出現,也就是說233,2333,23333,233333……這一系列的數不能在序列中出現。
1 i 輸出第i個元素。
2 a b x 將[a,b]區間的序列賦值為x。
3 a b x 將[a,b]區間的序列加上x。
4 a b 將區間[a,b]賦值為[a,b]中的最大值。
5 a b 將區間[a,b]賦值為[a,b]中的最小值。
6 a b 將區間[a,b]賦值為[a,b]中的平均值,平均值向下取整。
如果在操作後區間中出現了233之類的數,則需要將你剛才操作的那個區間的數全部加一,如果再出現,就再加一,直到不出現為止。
初始不會出現可怕的數字。資料範圍1e5,數值1e9+7。

題解:
分級,相同的區間視為縮成一個點,這樣複雜度不會超過兩個log。(其實平衡樹可以嚴格一個log但是常數大反而跑得不是很快。)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define
gc getchar()
#define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; typedef pair<int,int> pii; typedef set<int>::iterator sit; inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9'); x=ch^'0';while((ch=gc)>=
'0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; } const lint INF=LLONG_MAX/10-10;const int N=100010; lint kp[20];int kpc,a[N]; struct segment{ int l,r,pos;lint pt,vt; lint mn,mx,mndis,s; segment *ch[2]; }*rt; inline lint getnxt(lint x) { rep(i,0,kpc) if(kp[i]>=x) return kp[i]; return INF; } inline int push_up(segment* &rt) { rt->s=rt->ch[0]->s+rt->ch[1]->s, rt->mn=min(rt->ch[0]->mn,rt->ch[1]->mn), rt->mx=max(rt->ch[0]->mx,rt->ch[1]->mx), rt->mndis=min(rt->ch[0]->mndis,rt->ch[1]->mndis); if(rt->ch[0]->mndis<rt->ch[1]->mndis) rt->pos=rt->ch[0]->pos; else rt->pos=rt->ch[1]->pos;return 0; } int build(segment* &rt,int l,int r) { rt=new segment,rt->l=l,rt->r=r,rt->pt=0,rt->vt=-1;int mid=(l+r)>>1; if(l==r) return rt->mndis=getnxt(rt->mn=rt->mx=rt->s=a[rt->pos=l])-a[l],0; return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt); } inline int update_tags(segment* &rt,lint v,int tp) { int len=rt->r-rt->l+1; if(tp==1) { rt->mn=rt->mx=v,rt->s=v*len,rt->vt=v, rt->pt=0,rt->mndis=getnxt(v)-v,rt->pos=rt->l; } else{ rt->mn+=v,rt->mx+=v,rt->s+=v*len,rt->mndis-=v; if(rt->vt>=0) rt->vt+=v;else rt->pt+=v; } return 0; } inline int push_down(segment* &rt) { if(rt->vt>=0) { update_tags(rt->ch[0],rt->vt,1), update_tags(rt->ch[1],rt->vt,1), rt->vt=-1; } else if(rt->pt) { update_tags(rt->ch[0],rt->pt,2), update_tags(rt->ch[1],rt->pt,2), rt->pt=0; } return 0; } int update(segment* &rt,int s,int t,lint v,int tp) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) return update_tags(rt,v,tp); if(rt->pt||rt->vt>=0) push_down(rt); if(s<=mid) update(rt->ch[0],s,t,v,tp); if(mid<t) update(rt->ch[1],s,t,v,tp); return push_up(rt); } lint query(segment* &rt,int s,int t,int tp) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) return tp==1?rt->mx:(tp==2?rt->mn:rt->s); if(rt->pt||rt->vt>=0) push_down(rt);lint ans; ans=(tp==1?LLONG_MIN:(tp==2?LLONG_MAX:0)); if(s<=mid) { lint v=query(rt->ch[0],s,t,tp); ans=(tp==1?max(ans,v):(tp==2?min(ans,v):ans+v)); } if(mid<t) { lint v=query(rt->ch[1],s,t,tp); ans=(tp==1?max(ans,v):(tp==2?min(ans,v):ans+v)); } return ans; } int update_dis(segment* &rt,int p) { if(rt->mn==rt->mx) return rt->mndis=getnxt(rt->mx)-rt->mx,0; int l=rt->l,r=rt->r,mid=(l+r)>>1; if(rt->pt||rt->vt>=0) push_down(rt); return update_dis(rt->ch[p>mid],p),push_up(rt); } inline int adj(int l,int r) { while(rt->mndis<=0) { while(rt->mndis<0) update_dis(rt,rt->pos); while(rt->mndis==0) update(rt,l,r,1,2); } return 0; } int main() { kp[0]=233,kpc=16;rep(i,1,kpc) kp[i]=kp[i-1]*10+3; int n=inn(),q=inn(); rep(i,1,n) a[i]=inn(); build(rt,1,n); while(q--) { int tp=inn();lint x; if(tp==1) { int p=inn();printf("%lld\n",query(rt,p,p,3));continue; } int l=inn(),r=inn(); if(tp<=3) x=inn(); else x=query(rt,l,r,tp-3); if(tp==6) x/=(r-l+1); if(tp==3) update(rt,l,r,x,2),adj(l,r); else update(rt,l,r,getnxt(x)==x?x+1:x,1); } return 0; }