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)范围内
PS:由于数据6出错导致某些人只有90分,已于2016.5.13修正。
出题人在此对两位90分的用户表示诚挚的歉意
分类标签 Tags 点此展开
思路:区间赋值和区间加法综合操作。
先赋值,后加法。
注意:有一个全部赋值为0的情况。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100001 using namespace std; int n,m; struct nond{ int l,r; long long sum,max,min; long long flag1,flag2; }tree[MAXN*4]; void up(int now){ tree[now].sum=tree[now*2].sum+tree[now*2+1].sum; tree[now].min=min(tree[now*2].min,tree[now*2+1].min); tree[now].max=max(tree[now*2].max,tree[now*2+1].max); } void build(int now,int l,int r){ tree[now].l=l;tree[now].r=r; tree[now].flag2=-1; if(tree[now].l==tree[now].r){ scanf("%lld",&tree[now].sum); tree[now].min=tree[now].max=tree[now].sum; return ; } int mid=(tree[now].l+tree[now].r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); up(now); } void down(int now){ if(tree[now].flag2!=-1){ tree[now*2].flag2=tree[now].flag2; tree[now*2+1].flag2=tree[now].flag2; tree[now*2].flag1=tree[now*2+1].flag1=0; tree[now*2].min=tree[now*2].max=tree[now].flag2; tree[now*2+1].min=tree[now*2+1].max=tree[now].flag2; tree[now*2].sum=(tree[now*2].r-tree[now*2].l+1)*tree[now].flag2; tree[now*2+1].sum=(tree[now*2+1].r-tree[now*2+1].l+1)*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].min+=tree[now].flag1; tree[now*2+1].min+=tree[now].flag1; tree[now*2].max+=tree[now].flag1; tree[now*2+1].max+=tree[now].flag1; tree[now*2].sum+=(tree[now*2].r-tree[now*2].l+1)*tree[now].flag1; tree[now*2+1].sum+=(tree[now*2+1].r-tree[now*2+1].l+1)*tree[now].flag1; tree[now].flag1=0; } } void changeadd(int now,int l,int r,long long k){ if(tree[now].l==l&&tree[now].r==r){ tree[now].sum+=(tree[now].r-tree[now].l+1)*k; tree[now].min+=k;tree[now].max+=k;tree[now].flag1+=k; return ; } if(tree[now].flag1||tree[now].flag2!=-1) down(now); int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) changeadd(now*2,l,r,k); else if(l>mid) changeadd(now*2+1,l,r,k); else { changeadd(now*2,l,mid,k);changeadd(now*2+1,mid+1,r,k); } up(now); } void changeset(int now,int l,int r,long long k){ if(tree[now].l==l&&tree[now].r==r){ tree[now].min=k;tree[now].max=k; tree[now].flag1=0;tree[now].flag2=k; tree[now].sum=(tree[now].r-tree[now].l+1)*k; return ; } if(tree[now].flag1||tree[now].flag2!=-1) down(now); int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) changeset(now*2,l,r,k); else if(l>mid) changeset(now*2+1,l,r,k); else { changeset(now*2,l,mid,k);changeset(now*2+1,mid+1,r,k); } up(now); } long long querysum(int now,int l,int r){ if(tree[now].l==l&&tree[now].r==r) return tree[now].sum; if(tree[now].flag1||tree[now].flag2!=-1) down(now); int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return querysum(now*2,l,r); else if(l>mid) return querysum(now*2+1,l,r); else return querysum(now*2,l,mid)+querysum(now*2+1,mid+1,r); } long long querymax(int now,int l,int r){ if(tree[now].l==l&&tree[now].r==r) return tree[now].max; if(tree[now].flag1||tree[now].flag2!=-1) down(now); int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return querymax(now*2,l,r); else if(l>mid) return querymax(now*2+1,l,r); else return max(querymax(now*2,l,mid),querymax(now*2+1,mid+1,r)); } long long querymin(int now,int l,int r){ if(tree[now].l==l&&tree[now].r==r) return tree[now].min; if(tree[now].flag1||tree[now].flag2!=-1) down(now); int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return querymin(now*2,l,r); else if(l>mid) return querymin(now*2+1,l,r); else return min(querymin(now*2,l,mid),querymin(now*2+1,mid+1,r)); } int main(){ scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=m;i++){ char opt[10];int a,b;long long c; cin>>opt;scanf("%d%d",&a,&b); if(opt[0]=='a'){ scanf("%lld",&c); changeadd(1,a,b,c); } else if(opt[0]=='s'&&opt[1]=='e'){ scanf("%lld",&c); changeset(1,a,b,c); } else if(opt[0]=='s'&&opt[1]=='u') printf("%lld\n",querysum(1,a,b)); else if(opt[0]=='m'&&opt[1]=='a') printf("%lld\n",querymax(1,a,b)); else printf("%lld\n",querymin(1,a,b)); } }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。