1. 程式人生 > >CF438D The Child and Sequence(線段樹)

CF438D The Child and Sequence(線段樹)

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(線段樹)