给定一个大小为N 的整数数组array,我们定义两种操作:
<!--[if !supportLists]-->1) <!--[endif]-->Add(L, R, W)。即将子数组[L, R]中的元素,都累加一个整数W。
<!--[if !supportLists]-->2) <!--[endif]-->Min(L, R)。即返回子数组[L, R]之中,最小的一个元素的值。
其中L和R为数组的下标,且从0开始计数。当数组下标L > R时,我们认为这个子数组的元素包含array[L], array[L+1], … array[N – 1], array[0], array[1], … array[R]。
每个测试文件包含多个测试案例。
每个测试案例的第一行为整数N, 其中1 <= N <= 100000, 表示数组array的元素个数。
第二行将会输入N个数组元素a1, a2,… an,且-10^6 <= ai <= 10^6。
第三行将输入整数M,其中 100000 <= M <= 100000,代表接下来将会输入的操作数
余下的M行将会是具体的对数组的操作指令:若一行中含有3个整数参数,则该操作为Add操作,需要对array的元素进行更新操作,三个参数依次代表L, R以及W;若一行中只有两个参数,则该操作为Min操作,你需要返回当前子数组[L, R]之中最小的元素大小。对于所有的操作指令, 都满足0 <= L, R <= N – 1, -10^6 <= W <= 10^6。
对于每个测试案例中的所有Min操作,都返回其指定的操作值。
3 1 2 4 3 0 2 0 0 1 0 2
1 2
本题属于线段树在区间上修改、查询,应使用线段树的延迟更新算法
设置结构体struct node { int L,R; long long int Min; long long int w; node *left,*right; };
其中Min表示该区间最小值,w表示该区间的加因子
当需修改某段区间时并不修改到根节点(避免超时),而是滞留在某些小区间上(这些小区间的和等于需修改区间),记住及时修改路径上的Min
当需查询某段区间时则一顺把该路径上的w依次往下推,直到找到需查询区间为止
#include<iostream> #include<cstring> #include<string> #include<cstdio> using namespace std; const long long int nMin=1<<30; struct node { int L,R; long long int Min;//记录该区间最小值 long long int w;//记录该区间加因子 node *left,*right; }; node tree[100000*2+10]; int co; void Build(node *root,int a,int b) //建立一颗线段树,初始化 { root->L=a; root->R=b; root->w=0; root->Min=nMin; if(a!=b) { co++; root->left=tree+co; co++; root->right=tree+co; Build(root->left,a,(root->L+root->R)/2); Build(root->right,(root->L+root->R)/2+1,b); } } long long min(long long a,long long b) { if(a<b) return a; else return b; } void insert(node *root,int i,long long int s) //依次插入元素 { if(root->L==i&&root->R==i) { root->Min=s; return; } if(i<=(root->L+root->R)/2) insert(root->left,i,s); else insert(root->right,i,s); root->Min=min(root->Min,s); } void Add(node *root,int a,int b,long long int s) //线段树的延迟更新 { if(root->L==a&&root->R==b) { root->w+=s; return ; } if(b<=(root->L+root->R)/2) { Add(root->left,a,b,s); } else if(a>=(root->L+root->R)/2+1) { Add(root->right,a,b,s); } else { Add(root->left,a,(root->L+root->R)/2,s); Add(root->right,(root->L+root->R)/2+1,b,s); } // root->Min=min(root->right->Min,root->left->Min); root->Min=min(root->right->Min+root->right->w,root->left->Min+root->left->w); } long long Query(node *root,int a,int b) //查询 { if(root->L==a&&root->R==b) { return root->Min+root->w; } if(root->w!=0) { Add(root->left,root->L,(root->L+root->R)/2,root->w); Add(root->right,(root->L+root->R)/2+1,root->R,root->w); } root->Min+=root->w; root->w=0; if(b<=(root->L+root->R)/2) return Query(root->left,a,b); else if(a>=(root->L+root->R)/2+1) return Query(root->right,a,b); else { return min(Query(root->left,a,(root->L+root->R)/2), Query(root->right,(root->L+root->R)/2+1,b)); } } int main() { int j,i; long long int k; int n,m; int x,y; long long int z; char c; while(scanf("%d",&n)!=EOF) { co=0; Build(tree,1,n); for(i=1;i<=n;i++) { scanf("%lld",&k); insert(tree,i,k); } cin>>m; for(i=0;i<m;i++) { cin>>x>>y; c=getchar(); if(c!='\n') { scanf("%lld",&z); if(x<=y) Add(tree,x+1,y+1,z); else { Add(tree,x+1,n,z); Add(tree,1,y+1,z); } } else { long long num; if(x<=y) num=Query(tree,x+1,y+1); else { num=min(Query(tree,x+1,n),Query(tree,1,y+1)); } printf("%lld\n",num); } } } return 0; }