線段樹--CF438D The Child and Sequence
阿新 • • 發佈:2020-08-26
學校集訓的第二天不知不覺寫了道紫題(〃'▽'〃)(〃'▽'〃)(〃'▽'〃)
對於操作1和3,赤裸裸的線段樹板子。單點修改和區間求和複雜度都沒有什麼問題,關鍵就在取模。對一個數取模,假如一段區間最大值都比這個模數小,那無論怎麼改,其值都不會變,有了這個性質,我們可以去掉許多不必要的操作,由於一次取模至少會砍一半,所以在log的時間內就可以完成對一個數的所有取模操作,這樣就可做了,因此我們額外維護一個區間最大值即可。
之前對線段樹深惡痛絕,現在看他真的好美,另一道題花神遊歷各國可以試著練練手。
程式碼:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 #define ll long long
7 #define re register
8 #define il inline
9 const int maxn=1e6+10;
10 ll n,m,a[maxn],tree[2*maxn],lazy[2*maxn],x,y,k,mark,tree1[2*maxn];
11 il int ls(ll x){return x<<1;}
12 il int rs(ll x){return x<<1|1;}
13 il void pushup(ll x){
14 tree[x]=tree[ls(x)]+tree[rs(x)];
15 tree1[x]=max(tree1[ls(x)],tree1[rs(x)]);
16 }
17 il void build(ll x,ll l,ll r){
18 if(l==r){tree[x]=a[l];tree1[x]=a[l];return;}
19 ll mid=(l+r)>>1;
20 build(ls(x),l,mid);
21 build(rs(x),mid+1 ,r);
22 pushup(x);
23 }
24 il void update(ll x,ll l,ll r,ll k,ll w){
25 if (l==r&&r==k){tree[x]=w;tree1[x]=w;return;}
26 ll mid=(l+r)>>1;
27 if (k<=mid) update(ls(x),l,mid,k,w);
28 if (k>mid) update(rs(x),mid+1,r,k,w);
29 pushup(x);
30 }
31
32 il void update1(ll x,ll l,ll r,ll nl,ll nr,ll k){
33 if (tree1[x]<k) return;
34 if (nl<=l&&r<=nr&&l==r){tree[x]=(tree[x]%k);tree1[x]=(tree1[x]%k);return;}
35 ll mid=(l+r)>>1;
36 if (nl<=mid) update1(ls(x),l,mid,nl,nr,k);
37 if (nr>mid) update1(rs(x),mid+1,r,nl,nr,k);
38 pushup(x);
39 }
40 il ll query(ll x,ll l,ll r,ll nl,ll nr){
41 ll ans=0;
42 if (nl<=l&&r<=nr)return tree[x];
43 ll mid=(l+r)>>1;
44 if (nl<=mid) ans+=query(ls(x),l,mid,nl,nr);
45 if (nr>mid) ans+=query(rs(x),mid+1,r,nl,nr);
46 return ans;
47 }
48 il ll query1(ll x,ll l,ll r,ll nl,ll nr){
49 ll ans=0;
50 if (nl<=l&&r<=nr)return tree1[x];
51 ll mid=(l+r)>>1;
52 if (nl<=mid) ans=max(query1(ls(x),l,mid,nl,nr),ans);
53 if (nr>mid) ans=max(query1(rs(x),mid+1,r,nl,nr),ans);
54 return ans;
55 }
56 int main(){
57 // freopen("mod.in","r",stdin);
58 // freopen("mod.out","w",stdout);
59 scanf ("%d%d",&n,&m);
60 for (re ll i = 1;i <= n;i++) scanf ("%lld",&a[i]);
61 build (1,1,n);
62 for(re ll i = 1;i <= m;i++){
63 scanf ("%lld",&mark);
64 if (mark==1){
65 scanf ("%lld%lld",&x,&y);
66 ll tmp=query(1,1,n,x,y);
67 printf ("%lld\n",tmp);
68 }
69 if (mark==2){
70 scanf ("%lld%lld%lld",&x,&y,&k);
71 ll tmp=query1(1,1,n,x,y);
72 if (tmp<k) continue;
73 update1(1,1,n,x,y,k);
74 }
75 if (mark==3){
76 scanf ("%lld%lld",&k,&y);
77 update(1,1,n,k,y);
78 }
79 }
80 return 0;
81 }