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

给定一个大小为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;
}

你可能感兴趣的:(数据结构,线段树)