CUG@WH 1435Find the minimum(线段树成段更新)

Problem G: Find the minimum

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 60   Solved: 14
[ Submit][ Status][ Web Board]

Description

Given an integer array of size N, we define two kind of operators:
1. Add(L,R,W) : adding an integer W to every element in subarray[L,R];
2. Min(L,R) : returning the minimum number in subarray[L,R].
Note. L and R are the index of array starting from 0. L > R is possible. If L > R, the subarray is composed of array[L], array[L+1].....array[N-1], array[0], array[1],.....array[R].

Input

There are several test cases, processed to the end of file.
For each test, the first line contains two positive integers N and M. N is the size of array, and M is the number of the operation. 
The second line contains N array elements, a1, a2, a3, ...., and an.
Then in the following M lines, each line contains an operation. If the line contains three integers L,R and W, it means the add(L,R,W) operator should be involved. If the line contains two integers L,R , it means the Min(L,R) operator should be involved.
(0<N, M<100,000; 0<= ai <= 10^6; 0 <= L, R <= N – 1, -10^6 <= W <= 10^6。)

Output

 For each Min(L,R) operator in test case, output the return value.

Sample Input

3 31 2 40 20 0 10 2

Sample Output

12

HINT

the output value may be very large ,long long type is recommended!


给#define跪了。。。。

没想到被宏定义卡了一早上。。。

宏定义不是很快的样子么。。。

以后再也不乱用宏定义了。。。。

题目大意:给n个数,2种操作,第一种操作给一个区间,要查询该区间最小值,第二种操作给一个区间和一个值,给该区间所有数加上该值。注意区间0~n-1。如果给的区间r<l,则对0-r和l~n-1两个区间操作。

题目分析:这是今年地大邀请赛的G题。很裸的线段树。维护区间最小值,加一个lazy标记成段更新即可。比赛的时候顺利的1A了,今天听说挂出来了,顺便水一下,没想到跪了大半个早上。代码并不难写,关键是TLE。。。TLE?这不科学!然后就悲剧的从头到尾检查了n遍,提交了n遍,都是TLE。然后就各种手动优化输入,结果还是在超时的边缘徘徊。

然后突然看到有个求最小值的Min函数,今天用的#define宏定义的,比赛是写的函数。然后就抱着试试看的心态一改,。。。竟然过了。。。

注意给的数很大,int会溢出。

详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100005;
typedef long long ll;
//#define Min(a,b) (a)>(b)?(b):(a)

struct node
{
    ll min,lazy;
}tree[N<<2];
int n,m;

ll Min(ll a,ll b)
{
    return a > b?b:a;
}

void build(int num,int s,int e)
{
    tree[num].min = 0;
    tree[num].lazy = 0;
    if(s == e)
        return;
    int mid = (s + e)>>1;
    build(num<<1,s,mid);
    build(num<<1|1,mid + 1,e);
}

ll nextint()
{
    ll ret;
    char c;
    bool sig = false;
    while(isspace(c = getchar()))
        ;
    if(c == '-')
    {
        sig = true;
        c = getchar();
    }
    ret = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return sig ? -ret:ret;
}

void add(int num,int s,int e,int l,int r,int val)
{
    if(s == e)
    {
        tree[num].min += val;
        return;
    }
    if(s == l && e == r)
    {
        tree[num].lazy += val;
        return;
    }
    if(tree[num].lazy)
    {
        tree[num].min += tree[num].lazy;
        tree[num<<1].lazy += tree[num].lazy;
        tree[num<<1|1].lazy += tree[num].lazy;
        tree[num].lazy = 0;
    }
    int mid = (s + e)>>1;
    if(r <= mid)
        add(num<<1,s,mid,l,r,val);
    else
    {
        if(l > mid)
            add(num<<1|1,mid + 1,e,l,r,val);
        else
        {
            add(num<<1,s,mid,l,mid,val);
            add(num<<1|1,mid + 1,e,mid + 1,r,val);
        }
    }
    tree[num].min = Min(tree[num<<1].min + tree[num<<1].lazy,tree[num<<1|1].min + tree[num<<1|1].lazy);
}

ll query(int num,int s,int e,int l,int r)
{
    if(s == e)
        return tree[num].min + tree[num].lazy;
    if(s == l && e == r)
        return tree[num].lazy + tree[num].min;
    int mid = (s + e)>>1;
    if(tree[num].lazy)
    {
        tree[num].min += tree[num].lazy;
        tree[num<<1].lazy += tree[num].lazy;
        tree[num<<1|1].lazy += tree[num].lazy;
        tree[num].lazy = 0;
    }
    if(r <= mid)
        return query(num<<1,s,mid,l,r);
    else
    {
        if(l > mid)
            return query(num<<1|1,mid + 1,e,l,r);
        else
            return Min(query(num<<1,s,mid,l,mid),query(num<<1|1,mid + 1,e,mid + 1,r));
    }
}

void print(int num,int s,int e)
{
    if(s == e)
    {
        printf("%lld %lld\n",tree[num].min,tree[num].lazy);
        return;
    }
    int mid = (s + e)>>1;
    print(num<<1,s,mid);
    print(num<<1|1,mid + 1,e);
}

int main()
{
    ll i,l,r,w,op;
    while(~scanf("%lld%lld",&n,&m))
    {
        //build(1,1,n);
        memset(tree,0,sizeof(tree));
        for(i = 1;i <= n;i ++)
        {
            //scanf("%lld",&w);
            w = nextint();
            add(1,1,n,i,i,w);
        }
        while(m --)
        {
            //scanf("%lld%lld",&l,&r);
         //   char cc = getchar();
            l = nextint();
            r = getchar() - '0';
            char cc;
            while((cc = getchar()) >= '0' && cc <= '9')
                r = r * 10 + cc - '0';
            l ++;r ++;
            if(cc == ' ')
            {
                //scanf("%lld",&w);
                bool sig = false;
                cc = getchar();
                if(cc == '-')
                {
                    sig = true;
                    cc = getchar();
                }
                w = cc - '0';
                while((cc = getchar()) >= '0' && cc <= '9')
                    w = w * 10 + cc - '0';
                if(sig)
                    w = -w;
               // printf("w%lld\n",w);
                if(l > r)
                {
                    add(1,1,n,1,r,w);
                    add(1,1,n,l,n,w);
                }
                else
                    add(1,1,n,l,r,w);
            }
            else
            {
                if(l > r)
                    printf("%lld\n",Min(query(1,1,n,1,r),query(1,1,n,l,n)));
                else
                    printf("%lld\n",query(1,1,n,l,r));
            }
        }
    }
    return 0;
}
/*
3 5
1 2 4
0 2
0 0 1
0 2
2 0 -2
2 0

7 10
1 2 3 4 5 6 7
0 3
4 1 -3
0 6
0 2 4
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值