CF438D The Child and Sequence(線段樹)
阿新 • • 發佈:2019-02-09
include efi print ems new 代碼 names for its
題目鏈接:CF原網 洛谷
題目大意:維護一個長度為 $n$ 的正整數序列 $a$,支持單點修改,區間取模,區間求和。共 $m$ 個操作。
$1\le n,m\le 10^5$。其它數均為非負整數且 $\le 10^9$。
居然被這道水題卡了那麽久……
主要難點就是取模操作。
我們發現一個數 $x$ 模 $i(1\le i\le x)$:
$i\le\lfloor\frac{x}{2}\rfloor$ 時:余數小於除數,所以答案小於 $\lfloor\frac{x}{2}\rfloor$。
$i>\lfloor\frac{x}{2}\rfloor$ 時:答案就是 $x-i\$,也小於 $\lfloor\frac{x}{2}\rfloor$。
所以 $x$ 每次被取模都至少減小一半。
那……就是暴力線段樹!
線段樹再維護一個區間最大值,當模數大於區間最大值時,直接走人。
容易發現如果沒有單點修改操作,一個葉子節點最多被暴力到 $\log a_i$ 次。
有單點修改操作?那又怎樣?一共只會多 $m$ 個數而已啊!
時間復雜度 $O((n+m)\log n\log a_i)$。
代碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=100010; #define線段樹lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline int read(){ char ch=getchar();int x=0,f=0; while(ch<‘0‘ || ch>‘9‘) f|=ch==‘-‘,ch=getchar();while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return f?-x:x; } int n,m,a[maxn],mx[maxn*4]; ll sum[maxn*4]; //和要開long long inline void pushup(int o){ sum[o]=sum[o<<1]+sum[o<<1|1]; mx[o]=max(mx[o<<1],mx[o<<1|1]); } void build(int o,int l,int r){ if(l==r) return void(sum[o]=mx[o]=a[l]); int mid=(l+r)>>1; build(lson); build(rson); pushup(o); } void modify(int o,int l,int r,int p,int v){ if(l==r) return void(sum[o]=mx[o]=v); int mid=(l+r)>>1; if(mid>=p) modify(lson,p,v); else modify(rson,p,v); pushup(o); } ll query(int o,int l,int r,int ql,int qr){ if(l>=ql && r<=qr) return sum[o]; int mid=(l+r)>>1;ll ans=0; if(mid>=ql) ans+=query(lson,ql,qr); if(mid<qr) ans+=query(rson,ql,qr); return ans; } //以上基本操作,不解釋。。。 void modulo(int o,int l,int r,int ql,int qr,int v){ if(mx[o]<v) return; //模數大於最大值,走人 if(l==r) return void(sum[o]=mx[o]=sum[o]%v); //到葉子結點,暴力 int mid=(l+r)>>1; if(mid>=ql) modulo(lson,ql,qr,v); //暴力下去 if(mid<qr) modulo(rson,ql,qr,v); pushup(o); } int main(){ n=read();m=read(); FOR(i,1,n) a[i]=read(); build(1,1,n); FOR(i,1,m){ int op=read(),x=read(),y=read(); switch(op){ case 1:printf("%lld\n",query(1,1,n,x,y));break; case 2:modulo(1,1,n,x,y,read());break; case 3:modify(1,1,n,x,y); } } }
CF438D The Child and Sequence(線段樹)