<学习笔记> 线段树
例题:codevs 4927 线段树练习5
题面
1 有n个数和5种操作: 2 add a b c:把区间[a,b]内的所有数都增加c 3 set a b c:把区间[a,b]内的所有数都设为c 4 sum a b:查询区间[a,b]的区间和 5 max a b:查询区间[a,b]的最大值 6 min a b:查询区间[a,b]的最小值
输入描述 Input Description
1 第一行两个整数n,m,第二行n个整数表示这n个数的初始值 2 接下来m行操作,同题目描述
输出描述 Output Description
1 对于所有的sum、max、min询问,一行输出一个答案
样例输入 Sample Input
1 10 6 2 3 9 2 8 1 7 5 0 4 6 3 add 4 9 4 4 set 2 6 2 5 add 3 8 2 6 sum 2 10 7 max 1 7 8 min 3 6
样例输出 Sample Output
1 49 2 11 3 4
数据范围及提示 Data Size & Hint
1 10%:1<n,m<=10 2 30%:1<n,m<=10000 3 100%:1<n,m<=100000 4 保证中间结果在long long(C/C++)、int64(pascal)范围内
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 #define ll long long 8 #define Maxn 100010 9 10 ll N,M,a,b,c; 11 ll num[Maxn]; 12 string s; 13 14 struct leaf{ 15 ll l,r,add,sum,maxn,minn,flag; 16 }Tree[Maxn<<2]; 17 18 void Dodata(ll n) 19 { 20 Tree[n].sum=Tree[n<<1].sum+Tree[n<<1|1].sum; 21 Tree[n].maxn=max(Tree[n<<1].maxn,Tree[n<<1|1].maxn); 22 Tree[n].minn=min(Tree[n<<1].minn,Tree[n<<1|1].minn); 23 } 24 void DoSet(ll n,ll add) 25 { 26 Tree[n].add=add; 27 Tree[n].minn=Tree[n].maxn=add; 28 Tree[n].sum=(Tree[n].r-Tree[n].l+1)*add; 29 } 30 void Doadd(ll n,ll add) 31 { 32 Tree[n].add+=add; 33 Tree[n].minn+=add; 34 Tree[n].maxn+=add; 35 Tree[n].sum+=(Tree[n].r-Tree[n].l+1)*add; 36 } 37 void Build(ll n,ll l,ll r) 38 { 39 Tree[n].l=l,Tree[n].r=r; 40 if(l==r) 41 { 42 Tree[n].sum=Tree[n].maxn=Tree[n].minn=num[l]; 43 return ; 44 } 45 ll mid=(l+r)>>1; 46 Build(n<<1,l,mid); 47 Build(n<<1|1,mid+1,r); 48 Dodata(n); 49 } 50 void Spread(int n) 51 { 52 ll &ad=Tree[n].add; 53 if(Tree[n].flag) 54 { 55 Tree[n].flag=0; 56 Tree[n<<1].flag=Tree[n<<1|1].flag=1; 57 DoSet(n<<1,ad),DoSet(n<<1|1,ad); 58 ad=0; 59 return ; 60 } 61 Doadd(n<<1,ad); 62 Doadd(n<<1|1,ad); 63 ad=0; 64 } 65 void Add(ll n,ll l,ll r,ll add) 66 { 67 ll L=Tree[n].l,R=Tree[n].r; 68 if(l<=L&&r>=R) 69 { 70 Doadd(n,add); 71 return ; 72 } 73 Spread(n); 74 ll mid=(L+R)>>1; 75 if(l<=mid) Add(n<<1,l,r,add); 76 if(r>mid) Add(n<<1|1,l,r,add); 77 Dodata(n); 78 } 79 void Set(ll n,ll l,ll r,ll add) 80 { 81 ll L=Tree[n].l,R=Tree[n].r; 82 if(l<=L&&r>=R) 83 { 84 Tree[n].flag=1; 85 DoSet(n,add); 86 return ; 87 } 88 Spread(n); 89 ll mid=(L+R)>>1; 90 if(l<=mid) Set(n<<1,l,r,add); 91 if(r>mid) Set(n<<1|1,l,r,add); 92 Dodata(n); 93 } 94 ll Ask_Sum(ll n,ll l,ll r) 95 { 96 ll L=Tree[n].l,R=Tree[n].r; 97 if(l<=L&&r>=R) 98 return Tree[n].sum; 99 Spread(n); 100 ll mid=(L+R)>>1; 101 ll Ans=0; 102 if(l<=mid) Ans+=Ask_Sum(n<<1,l,r); 103 if(r>mid) Ans+=Ask_Sum(n<<1|1,l,r); 104 return Ans; 105 } 106 ll Ask_Max(ll n,ll l,ll r) 107 { 108 ll L=Tree[n].l,R=Tree[n].r; 109 if(l<=L&&r>=R) 110 return Tree[n].maxn; 111 Spread(n); 112 ll mid=(L+R)>>1; 113 ll Ans=-(1e9+7); 114 if(l<=mid) Ans=max(Ans,Ask_Max(n<<1,l,r)); 115 if(r>mid) Ans=max(Ans,Ask_Max(n<<1|1,l,r)); 116 return Ans; 117 } 118 ll Ask_Min(ll n,ll l,ll r) 119 { 120 ll L=Tree[n].l,R=Tree[n].r; 121 if(l<=L&&r>=R) 122 return Tree[n].minn; 123 Spread(n); 124 ll mid=(L+R)>>1; 125 ll Ans=1e9+7; 126 if(l<=mid) Ans=min(Ans,Ask_Min(n<<1,l,r)); 127 if(r>mid) Ans=min(Ans,Ask_Min(n<<1|1,l,r)); 128 return Ans; 129 } 130 int main() 131 { 132 scanf("%lld%lld",&N,&M); 133 for(int i=1;i<=N;++i) 134 scanf("%lld",&num[i]); 135 Build(1,1,N); 136 while(M--) 137 { 138 cin>>s; 139 if(s=="add") scanf("%lld%lld%lld",&a,&b,&c), 140 Add(1,a,b,c); 141 if(s=="set") scanf("%lld%lld%lld",&a,&b,&c), 142 Set(1,a,b,c); 143 if(s=="sum") scanf("%lld%lld",&a,&b), 144 printf("%lld\n",Ask_Sum(1,a,b)); 145 if(s=="max") scanf("%lld%lld",&a,&b), 146 printf("%lld\n",Ask_Max(1,a,b)); 147 if(s=="min") scanf("%lld%lld",&a,&b), 148 printf("%lld\n",Ask_Min(1,a,b)); 149 } 150 return 0; 151 }