题解--Stone的txl数

 题目

**Problem Description
Stone 将一个序列中 m 个区间的和命名为 txl 数(区间重叠部分只取一次)。
现在,Stone 从 QAQ 的桌子上获得了一个序列,他想知道这个序列的 txl 数是多少。
Input
输入数据有多组(数据组数不超过 50),到 EOF 结束。
每组数据第一行为两个数 n, m (1 <= n <= 10^5, 1 <= m <= 1000),分别代表序列的长度和区间的个数。
第二行为 n 个数代表该序列,(1 <= a[i] <= 10^7);接下来 m 行每行两个数 l, r (1 <= l <= r <= n),代表区间 [l, r]。
Output
对于每组数据,输出一行,表示该序列的 txl 数。
Example Input
10 3
1 2 3 4 5 6 7 8 9 10
1 3
2 4
3 5
Example Output
15

题目的数据量非常大,如果用标记数组for循环暴力做的话会超时
我的做法是:用结构体存起来所有的区间,按区间的左边界从小到大排序
再设一个单独的变量 l, r,用来存一个连续区间的左右边界

一、先让l,r等于结构体里面的第一个元素的左边界和右边界,然后到后面的元素里搜索
二、后面的元素有两种情况:
1. 后面元素的左边界小于等于单独的变量r 也就是说后面的元素和单独的l、r区间是连续的,不是断开的,把这两个区间合并。然后查找在后面一个元素是否和l、r这个区间连续。
2. 后面元素的左边界大于单独的比昂两r 也就是说后面的元素和单独的l、r区间是不连续的,求出l、r这个区间的元素和。

这样每一个l、r区间是能组成连续区间的 几个结构体里的 区间的 并区间。把结构体遍历完后,即可求出答案。

Ps:注意变量是否会爆出来,在适当的地方用long long类型

最后贴上我的代码(f1和f2是快排函数)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct interval
{
    int r, l;
}b[11234], t;

void f1(int, int);
int f2(int, int);

int main()
{
    int i, n, m, le, ri;
    long long sum, a[112345];
    while(~scanf("%d %df", &n, &m))
    {
        a[0] = 0;
        sum = 0;
        for(i=1; i<=n; i++)
        {
            scanf("%lld", &a[i]);
            a[i] += a[i-1];
        }
        for(i=1; i<=m; i++)
            scanf("%d %d", &b[i].l, &b[i].r);
        f1(1, m);
//        for(i=1; i<=m; i++)
//            printf("%d %d\n", b[i].l, b[i].r);
        i = 1;
        while(i <= m)
        {
            le = b[i].l;
            ri = b[i].r;
            i ++;
            while(i <= m && ri >= b[i].l)
            {
                ri = b[i].r > ri ? b[i].r : ri;
                i ++;
            }
//            printf("l:%d r:%d\n", le, ri);
            sum += a[ri] - a[le-1];
        }
        printf("%lld\n", sum);
    }
    return 0;
}
void f1(int left, int right)
{
    int mid;
    if(left < right)
    {
        mid = f2(left, right);
        f1(left, mid-1);
        f1(mid+1, right);
    }
}
int f2(int left, int right)
{
    t = b[left];
    while(left < right)
    {
        while(left < right && b[right].l >= t.l)
            right --;
        b[left] = b[right];
        while(left < right && b[left].l <= t.l)
            left ++;
        b[right] = b[left];
    }
    b[left] = t;
    return left;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值