codevs4927 线段树练习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)范围内

 


正解:线段树

解题报告:

  这就是传说中的线段树综合题,所有标记都有。

  注意一点,就是我的执行顺序是先add标记下传,然后才是set标记下传,但下传过程中set可以覆盖add。开始我一直WA,后来才发现了一个错误,就是我先执行的add,那么,如果当前结点上此时既有set又有add,那么只能说明add一定是在set之后执行的,不然执行set的时候add早已经下传,所以我可以考虑直接把add的值直接加在set上去,就可以避免有一部分add没有发挥作用。害得我调试了半个小时。

 

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <ctime>
  9 #include <vector>
 10 #include <queue>
 11 #include <map>
 12 #include <set>
 13 using namespace std;
 14 typedef long long LL;
 15 #define RG register
 16 const int MAXN = 100011;
 17 int n,m,ql,qr;
 18 LL val,ans,inf;
 19 char ch[10];
 20 struct node{
 21     int l,r;
 22     LL minl,maxl,sum,add,set;
 23     bool flag;
 24 }a[MAXN*3];
 25 
 26 inline LL getint(){RG LL w=0,q=0; char c=getchar();while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;}
 27 
 28 inline void update(RG int root){
 29     RG int lc=root*2,rc=lc+1;  a[root].maxl=max(a[lc].maxl,a[rc].maxl);
 30     a[root].sum=a[lc].sum+a[rc].sum;  a[root].minl=min(a[lc].minl,a[rc].minl);
 31 }
 32 
 33 inline void build(RG int root,RG int l,RG int r){
 34     a[root].l=l; a[root].r=r;
 35     if(l==r) {    a[root].minl=a[root].maxl=a[root].sum=getint();    return ;  }
 36     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1;
 37     build(lc,l,mid); build(rc,mid+1,r); update(root);
 38 }
 39 
 40 inline void pushdown(int root,int l,int r){
 41     if(!a[root].flag) return ; if(l==r) { a[root].flag=false; a[root].set=0; return ; }
 42     int lc=root*2,rc=lc+1; int mid=(l+r)/2;
 43     a[lc].set=a[rc].set=a[root].set; a[root].add=a[lc].add=a[rc].add=0;
 44     a[lc].maxl=a[rc].maxl=a[lc].minl=a[rc].minl=a[root].set;
 45     a[lc].sum=(LL)(mid-l+1)*a[root].set; a[rc].sum=(LL)(r-mid)*a[root].set;  a[root].sum=a[lc].sum+a[rc].sum;
 46     a[lc].flag=a[rc].flag=true;
 47     a[root].set=0; a[root].flag=false;
 48 }
 49 
 50 inline void pushdown_add(RG int root,RG int l,RG int r){
 51     if(l==r) { a[root].add=0; return ; } if(a[root].add==0) return ;
 52  
 53     if(a[root].flag){ a[root].set+=a[root].add; a[root].add=0; return ; }//至关重要,因为add打在set的后面,这就意味着相当于我们可以把set设的值变大一点
 54 
 55     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; a[lc].add+=a[root].add; a[rc].add+=a[root].add;    
 56     a[lc].minl+=a[root].add; a[lc].maxl+=a[root].add; a[rc].minl+=a[root].add; a[rc].maxl+=a[root].add;
 57     a[lc].sum+=a[root].add*(LL)(mid-l+1); a[rc].sum+=a[root].add*(LL)(r-mid);
 58     a[root].add=0; a[root].sum=a[lc].sum+a[rc].sum;
 59 }
 60 
 61 inline void add(RG int root,RG int l,RG int r){
 62     pushdown_add(root,l,r); pushdown(root,l,r); 
 63     if(ql<=l && r<=qr) { a[root].add+=val; a[root].maxl+=val; a[root].minl+=val; a[root].sum+=val*(LL)(r-l+1); return ; }
 64     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; if(ql<=mid) add(lc,l,mid); if(qr>mid) add(rc,mid+1,r);
 65     update(root);
 66 }
 67 
 68 inline void update_set(RG int root,RG int l,RG int r){    
 69     if(ql<=l && r<=qr) { a[root].flag=true; a[root].minl=a[root].maxl=a[root].set=val; a[root].add=0; a[root].sum=(LL)(r-l+1)*val; return ; } 
 70     pushdown_add(root,l,r); pushdown(root,l,r);
 71     RG int mid=(l+r)/2;RG int lc=root*2,rc=lc+1;
 72     if(ql<=mid) update_set(lc,l,mid); if(qr>mid) update_set(rc,mid+1,r); update(root);
 73 }
 74 
 75 inline void query_sum(RG int root,RG int l,RG int r){
 76     pushdown_add(root,l,r);  pushdown(root,l,r);
 77     if(ql<=l && r<=qr){ ans+=a[root].sum; return ; }
 78     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 79     if(ql<=mid) query_sum(lc,l,mid); if(qr>mid) query_sum(rc,mid+1,r); update(root);
 80 }
 81 
 82 inline void query_max(RG int root,RG int l,RG int r){
 83     pushdown_add(root,l,r); pushdown(root,l,r);
 84     if(ql<=l && r<=qr){ ans=max(a[root].maxl,ans); return ; }
 85     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 86     if(ql<=mid) query_max(lc,l,mid); if(qr>mid) query_max(rc,mid+1,r); update(root);
 87 }
 88 
 89 inline void query_min(RG int root,RG int l,RG int r){
 90     pushdown_add(root,l,r); pushdown(root,l,r);
 91     if(ql<=l && r<=qr){ ans=min(a[root].minl,ans); return ; }
 92     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 93     if(ql<=mid) query_min(lc,l,mid); if(qr>mid) query_min(rc,mid+1,r); update(root);
 94 }
 95 
 96 inline void work(){
 97     n=getint(); m=getint(); build(1,1,n); inf=1; for(RG int i=1;i<=62;i++) inf*=2;
 98     while(m--) {
 99     scanf("%s",ch);
100     if(ch[0]=='a') { ql=getint(); qr=getint(); val=getint(); add(1,1,n); }
101     else if(ch[0]=='s' && ch[1]=='e') { ql=getint(); qr=getint(); val=getint(); update_set(1,1,n); }
102     else if(ch[0]=='s' && ch[1]=='u') { ql=getint(); qr=getint(); ans=0; query_sum(1,1,n); printf("%lld\n",ans); }
103     else if(ch[0]=='m' && ch[1]=='a') { ql=getint(); qr=getint(); ans=-inf; query_max(1,1,n); printf("%lld\n",ans); }
104     else{ ql=getint(); qr=getint(); ans=inf; query_min(1,1,n); printf("%lld\n",ans); }
105     }
106 }
107 
108 int main()
109 {
110   work();
111   return 0;
112 }

 

posted @ 2016-09-17 19:37  ljh_2000  阅读(425)  评论(0编辑  收藏  举报