NUIST OJ 1352 回顾 【差分】

NUIST OJ 1352 回顾 【差分】

题目

题目描述

第三次选择那些大晴天的日子,第三次行走在孤单的海岸线,第三次静静地种更多的花给自己看~
我们假设把海岸线分为n块,每块的分别标记为1…n,每块都可以种花,每次种花可以选择某个[left,right]的闭区间,每块种上一朵花.经过m次种花操作后, 输入t次区间, 根据输入的区间,求该区间内花的总数.
注意这一次,我们要看更多次的花儿,所以在第一行要输入看花的次数t

输入描述:

多组输入
对每组输入,第一行有三个整数n m t,分别代表总块数和种花的次数以及我们希望查询区间的次数.
(1 <= n, m, t<= 100000)
接下来的m行, 每行两个整数 L,R 代表[L,R]区间内每块种上一朵花.(1 <= L <= R <= n)
接下来的t行, 每行输入两个整数 a,b 代表最后要查询的花的总数的区间.(1 <= a <= b <= n)

原问题:

原问题详见
NUIST OJ 1350-1352 面朝大海,春暖花开【初识线段树】

差分是什么

所谓差分,以大家高中学到的数列概念来理解。
假设

n123……n
Dn013……i
An125……An-1 +i
Sn138……Sn-1 + An

类似于这样的差值数列。
那么在本题中,在[a,b]区间上种花,实际上带来的结果就是,a比a-1的值多1,即Dn(n=a)加了1。这样,从a区间开始往后的每一个区间,因为An(n=a)的值加了1,而他们和前一项的差值Dn(n>a)没有改变,所以实际上他们的An(n>a)都比原来大了1。而到B结束则可以将Dn(n=b+1)的值减1,这样从b+1开始,后面的值都不会受到此次操作的影响了。这样,仅仅通过对两个Dn的改变,实际上修改了整整一串的值。大大减少了时间消耗。

求An数组和Sn数组

只需要利用公式,An=An-1+Dn即可计算出An;Sn=Sn-1+An即可计算出Sn
实际上就是对数组进行了两次循环加和的操作

快速求区间和

有了Sn数组,求区间和的操作就快很多了,不需要将区间内的An一个个加起来;
At~Al的和可以用Sl-St-1求得

代码呈现

#include<cstdio>
#include<cstring>
using namespace std;
int dat[100010];
int main()
{
    int n, m, t, l, f, a, b;
    while (scanf_s("%d %d %d",&n,&m,&t)!=EOF) {
        memset(dat, 0, (n + 1)*sizeof(int));
        for (int i = 0; i<m; i++) {
            scanf("%d %d",&l,&f);
            dat[l] += 1;
            dat[f + 1] -= 1;
        }
        for (int i = 1; i <= n; i++)
            dat[i] += dat[i - 1];
        for (int i = 1; i <= n; i++)
            dat[i] += dat[i - 1];
        for (int i = 0; i<t; i++) {
            scanf("%d %d", &a, &b);
            printf("%d\n", dat[b] - dat[a - 1]);
        }
    }
    return 0;
}

随便说说

差分在处理区段求和上有非凡的表现。虽然曾经我们都学过数列,但是真正用起来的时候却完全想不到它。渍渍渍,遗憾呐。
另外,差分在这里有一个小缺陷。必须所有数据全部录入完毕之后,根据完整的Dn表格生成An表格,再根据An的表格生成Sn的表格。若是生成完毕之后其中有一处需要修改,那么需要重新生成Dn和Sn,这样就失去了它的独特优势。

后记

照例膜拜ThinkSpirit各位大佬
第一个想到这个方法的大佬解说如下
THINKSPIRIT ALGORITHM TEAM TASK #1 解题报告

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值