首页 > 技术文章 > 洛谷5026 Lycanthropy 差分套差分

anyixing-fly 2020-03-08 22:01 原文

题目链接

  https://www.luogu.com.cn/problem/P5026

题意

  在一个长度为m的序列中,每次给一个下标x,和一个权值v,然后从x-v*3到x-v*2单调递增,从x-v*2到x单调递减,从x到x+v*2再次递增,然后x+v*2到x+v*3递减,递增递减都是斜率绝对值为1的直线。

分析

  刚学了差分趁现在还没忘赶紧把自己想的写下来

  看到这个其实很容易想到,对于每次修改,将其分为四个区间进行修改,由于它是单调递增的,所以让每个点对应的差分数组加一就行,这样就用到了线段树维护差分数组,但这样还是效率不是很高,我们仍然可以优化,对于同一区间内的每个点与前一个点的差值也是一定的,所以只要修改区间的两端就可以使整个区间内的差值改变,这样两个点的差值就可以构成一个差分数组,然后通过对这个差分数组求前缀和,可以得到每个点与前一个点的差值,再然后更新每个点值的前缀和数组,然后就可以得到这个点的值,输出就行,也就是rt,差分套差分。

  其实这个挺简单的,仔细想想也  很容易    困难想得出来

  最后是关于负数的问题,数组下标是不能为负数的,会RE,某大佬的做法是将原点左移,我试了试也是可以的,后来在洛谷上学习了一篇题解的做法,觉得这个很不错,直接用一个指针来代替数组,其实数组的实质也是指针,比如数组aa[10]->从指针aa开始往后数10个,所以只要让一个指针指向数组中间就能实现负下标的数组,感觉挺实用 好玩。

  

 1 #include<cstdio>
 2 const int N=2e6;//记得开大点,不然会被一些极大的数据RE掉
 3 int aa[N<<1],bb[N<<1];
 4 int main(){
 5     int *a=aa+N,*b=bb+N;
 6     int m,n;
 7     scanf("%d%d",&n,&m);
 8     for(int i=1;i<=n;i++){
 9         int v,x;
10         scanf("%d%d",&v,&x);
11         a[x-v*3+1]++;
12         a[x-v*2+1]-=2;
13         a[x+1]+=2;
14         a[x+v*2+1]-=2;
15         a[x+v*3+1]++;
16     }
17     for(int i=-40000;i<=40000+m;i++)
18         a[i]+=a[i-1],b[i]+=b[i-1]+a[i];
19     for(int i=1;i<=m;i++)
20         printf("%d ",b[i]);
21     return 0;
22 }

 

 

小正方形的每个朋友有一个体积数值 vv,当体积为 vv 的一个朋友跳入水中,我们设入水点为 ii,将会导致 i - v + 1iv+1 到 ii 的水位依次降低 1,2,\cdots,v1,2,,v

同样地,第 ii 到 i + v - 1i+v1 的水位会依次降低 v,v - 1,\cdots,1v,v1,,1.

相对应地,i - viv 的水位不变, i - v - 1iv1 到 i - 2 * vi2v 水位依次增加 1,2,\cdots,v1,2,,v, i - 2 * vi2v 到 i - 3 * v + 1i3v+1 水位依次增加 v,v - 1,\cdots,1v,v1,,1

同样,i + vi+v 水位不变,i + v + 1i+v+1 到 i + 2 * vi+2v 水位增加 1,2,\cdots,v1,2,,vi + 2 * vi+2v 到 i + 3 * v - 1i+3v1 水位依次增加 v,v - 1,\cdots,1v,v1,,1

推荐阅读