序列操作 - 線段樹
阿新 • • 發佈:2018-11-24
題目大意:你要維護一個長度為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;
}