1. 程式人生 > >codevs 4927 線段樹練習5

codevs 4927 線段樹練習5

inpu lag little sign AR 註意 ostream scan bsp

                codevs 4927 線段樹練習5

題目描述 Description

有n個數和5種操作

add a b c:把區間[a,b]內的所有數都增加c

set a b c:把區間[a,b]內的所有數都設為c

sum a b:查詢區間[a,b]的區間和

max a b:查詢區間[a,b]的最大值

min a b:查詢區間[a,b]的最小值

輸入描述 Input Description

第一行兩個整數n,m,第二行n個整數表示這n個數的初始值

接下來m行操作,同題目描述

輸出描述 Output Description

對於所有的sum、max、min詢問,一行輸出一個答案

樣例輸入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

樣例輸出 Sample Output

49

11

4

數據範圍及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保證中間結果在long long(C/C++)、int64(pascal)範圍內

考察算法:線段樹雙重標記

思路:線段樹區間加法和區間賦值

先賦值,後加法(賦值後,之前的加法失效)

註意:有將區間內的數都賦為0的情況

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 100001
#define LL long long
using namespace std;
int n, m, x, y;
LL z;
string s;
bool sign;
struct nond {
    int ll, rr;
    LL flag1, flag2, sum;
    LL minn, maxn;
}tree[4*N];
void
up(int now) { tree[now].sum = tree[now*2].sum+tree[now*2+1].sum; tree[now].maxn = max(tree[now*2].maxn, tree[now*2+1].maxn); tree[now].minn = min(tree[now*2].minn, tree[now*2+1].minn); } void down(int now) { if(tree[now].flag2!=-1) { tree[now*2].flag1 = tree[now*2+1].flag1 = 0; tree[now*2].flag2 = tree[now].flag2; tree[now*2+1].flag2 = tree[now].flag2; tree[now*2].sum = (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag2; tree[now*2+1].sum = (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag2; tree[now*2].maxn = tree[now].flag2; tree[now*2+1].maxn = tree[now].flag2; tree[now*2].minn = tree[now].flag2; tree[now*2+1].minn = tree[now].flag2; tree[now].flag2 = -1; } if(tree[now].flag1) { tree[now*2].flag1 += tree[now].flag1; tree[now*2+1].flag1 += tree[now].flag1; tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag1; tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag1; tree[now*2].maxn += tree[now].flag1; tree[now*2+1].maxn += tree[now].flag1; tree[now*2].minn += tree[now].flag1; tree[now*2+1].minn += tree[now].flag1; tree[now].flag1 = 0; } return ; } void build(int now, int l, int r) { tree[now].ll = l; tree[now].rr = r; tree[now].flag1 = 0; tree[now].flag2 = -1; if(l == r) { scanf("%lld", &tree[now].sum); tree[now].maxn = tree[now].sum; tree[now].minn = tree[now].sum; return ; } int mid = (l+r) / 2; build(now*2, l, mid); build(now*2+1, mid+1, r); up(now); } void add(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) { tree[now].flag1 += z; tree[now].sum += (tree[now].rr-tree[now].ll+1) * z; tree[now].maxn += z; tree[now].minn += z; return ; } if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) add(now*2, l, mid), add(now*2+1, mid+1, r); else if(r<=mid) add(now*2, l, r); else add(now*2+1, l, r); up(now); } void set(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) { tree[now].flag2 = z; tree[now].flag1 = 0; tree[now].sum = (tree[now].rr-tree[now].ll+1) * z; tree[now].maxn = tree[now].minn = z; return ; } if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) set(now*2, l, mid), set(now*2+1, mid+1, r); else if(r<=mid) set(now*2, l, r); else set(now*2+1, l, r); up(now); } LL query(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].sum; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return query(now*2, l, mid) + query(now*2+1, mid+1, r); else if(r<=mid) return query(now*2, l, r); else return query(now*2+1, l, r); } LL little(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].minn; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return min(little(now*2, l, mid), little(now*2+1, mid+1, r)); else if(r<=mid) return little(now*2, l, r); else return little(now*2+1, l, r); } LL large(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].maxn; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return max(large(now*2, l, mid), large(now*2+1, mid+1, r)); else if(r<=mid) return large(now*2, l, r); else return large(now*2+1, l, r); } int main() { scanf("%d%d", &n, &m); build(1, 1, n); for(int i = 1; i <= m; i++) { cin >> s; if(s[1] == d) { scanf("%d%d%lld", &x, &y, &z); add(1, x, y); continue; } if(s[1] == e) { scanf("%d%d%lld", &x, &y, &z); set(1, x, y); continue; } if(s[1] == u) { scanf("%d%d", &x, &y); printf("%lld\n", query(1, x, y)); continue; } if(s[1] == i) { scanf("%d%d", &x, &y); printf("%lld\n", little(1, x, y)); continue; } if(s[1] == a) { scanf("%d%d", &x, &y); printf("%lld\n", large(1, x, y)); continue; } } return 0; }

codevs 4927 線段樹練習5