【LOJ#6029】市場(線段樹)
阿新 • • 發佈:2018-12-27
【LOJ#6029】市場(線段樹)
題面
題解
看著就是一個需要勢能分析的線段樹。
不難發現就是把第二個整除操作化為減法。
考慮一下什麼時候整除操作才能變成減法。
假設兩個數為\(a,b\)。那麼就有\(\displaystyle a-[\frac{a}{d}]=b-[\frac{b}{d}]\)。
那麼假設\(a,b\)整除的結果分別為\(aa,bb\)。\(a=d*aa+p_a,b=d*bb+p_b\)
得到:\(\displaystyle (d-1)aa+p_a=(d-1)bb+p_b\)
化簡後得到:\(\displaystyle (d-1)(aa-bb)=p_b-p_a\)
顯然\(p_a,p_b\)的取值範圍就是\([0,d)\),而左邊還乘了一個\(d-1\)。也就意味著這個限制是非常強的,假設\(aa>bb\)(等於就必定相等了,沒什麼好考慮的),那麼\(p_b-p_b\in[0,d)\)。左邊顯然只能取\(1\),右邊顯然只能去\(d-1\)。寫出來就是:\(a=d*aa,b=d*(aa-1)+d-1\)。所以我們得到\(a-b=1\)。
因此維護區間最大值和最小值,如果最大值和最小值整除操作之後的差相等,那麼可以變為區間減法。否則暴力下放。
至於複雜度?聽\(zsy\)口胡了一下他的分析。單獨考慮一個線段樹節點,它最多被暴力訪問\(loga\)次。如果區間加法則重置這個\(log\)
感覺很對的樣子。
注意一下負數的向下取整。
#include<iostream> #include<cstdio> using namespace std; #define ll long long #define MAX 100100 #define lson (now<<1) #define rson (now<<1|1) inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Node{ll v;int mn,mx,tag;}t[MAX<<2]; void pushup(int now) { t[now].mn=min(t[lson].mn,t[rson].mn); t[now].mx=max(t[lson].mx,t[rson].mx); t[now].v=t[lson].v+t[rson].v; } void Build(int now,int l,int r) { if(l==r){t[now].v=t[now].mn=t[now].mx=read();return;} int mid=(l+r)>>1; Build(lson,l,mid);Build(rson,mid+1,r); pushup(now); } void puttag(int now,int l,int r,int w) { t[now].v+=(r-l+1)*w; t[now].tag+=w;t[now].mn+=w;t[now].mx+=w; } void pushdown(int now,int l,int r) { if(!t[now].tag)return; int mid=(l+r)>>1; puttag(lson,l,mid,t[now].tag); puttag(rson,mid+1,r,t[now].tag); t[now].tag=0; } void Modify(int now,int l,int r,int L,int R,int w) { if(L<=l&&r<=R){puttag(now,l,r,w);return;} int mid=(l+r)>>1;pushdown(now,l,r); if(L<=mid)Modify(lson,l,mid,L,R,w); if(R>mid)Modify(rson,mid+1,r,L,R,w); pushup(now); } int Div(int a,int d) { if(a>=0)return a/d-a; if(a%d==0)return a/d-a; return a/d-1-a; } void ModifyDiv(int now,int l,int r,int L,int R,int d) { if(L<=l&&r<=R) if(Div(t[now].mx,d)==Div(t[now].mn,d)) {puttag(now,l,r,Div(t[now].mx,d));return;} int mid=(l+r)>>1;pushdown(now,l,r); if(L<=mid)ModifyDiv(lson,l,mid,L,R,d); if(R>mid)ModifyDiv(rson,mid+1,r,L,R,d); pushup(now); } ll Query(int now,int l,int r,int L,int R) { if(L<=l&&r<=R)return t[now].v; int mid=(l+r)>>1;pushdown(now,l,r); ll ret=0; if(L<=mid)ret+=Query(lson,l,mid,L,R); if(R>mid)ret+=Query(rson,mid+1,r,L,R); return ret; } int Querymn(int now,int l,int r,int L,int R) { if(L==l&&r==R)return t[now].mn; int mid=(l+r)>>1;pushdown(now,l,r); if(R<=mid)return Querymn(lson,l,mid,L,R); if(L>mid)return Querymn(rson,mid+1,r,L,R); return min(Querymn(lson,l,mid,L,mid),Querymn(rson,mid+1,r,mid+1,R)); } int n,Q; int main() { n=read();Q=read(); Build(1,1,n); while(Q--) { int opt=read(),l=read()+1,r=read()+1; if(opt==1)Modify(1,1,n,l,r,read()); if(opt==2)ModifyDiv(1,1,n,l,r,read()); if(opt==3)printf("%d\n",Querymn(1,1,n,l,r)); if(opt==4)printf("%lld\n",Query(1,1,n,l,r)); } return 0; }