九度1407(线段树+延迟更新)

来源:互联网 发布:单片机交通灯控制系统 编辑:程序博客网 时间:2024/05/17 23:16

给定一个大小为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操作,都返回其指定的操作值。

样例输入:
31 2 430 20 0 10 2
样例输出:
12
本题属于线段树在区间上修改、查询,应使用线段树的延迟更新算法
设置结构体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);    elseinsert(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;}