一、差分标记介绍
差分标记用来解决针对区间(修改-查询)的问题,复杂度比线段树要更低。推荐这个博客。
例如,给数组中处于某个区间的数进行加减操作,然后查询某个位置上数的变化值。
二、HDU1556 Color the ball
2.1题意
N个气球依次编号为1,2,3....N.每次给定2个整数a b(a <= b),从气球a开始到气球b依次给每个气球涂一次颜色。求查询每个气球被涂的次数。
2.2分析
这里所有初始值为0,最后答案就是经过差分标记得到的变化值。
2.3代码
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 const int maxn = 1e5+10; 6 int sum[maxn]; 7 int N; 8 void Init() 9 { 10 memset(sum,0,sizeof(sum)); 11 } 12 void Solve() 13 { 14 int l,r; 15 for(int i=0;i<N;i++) 16 { 17 scanf("%d%d",&l,&r); 18 sum[l]++; 19 sum[r+1]--; 20 } 21 int res = 0; 22 for(int i=1;i<N;i++) 23 { 24 res += sum[i]; 25 printf("%d ",res); 26 } 27 res += sum[N]; 28 printf("%d ",res); 29 } 30 int main() 31 { 32 while(scanf("%d",&N)!=EOF) 33 { 34 if(N==0) break; 35 Init(); 36 Solve(); 37 } 38 return 0; 39 }
三、牛客contest 135-I 区间(题面)
3.1题意
有一个n个元素的数组a,对a[L]-a[R]进行M次操作:将a[L]-a[R]内的元素都加上P,询问a[l]-a[r]内的元素之和
3.2分析
经过M次操作的元素值等于初始值加上变化值,所以用差分标记得到变化值最后输出时再与原始值相加即可。注意会爆int以及不要开多个大数组。
3.3代码
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 const int maxn = 1e6+10; 6 int n,M; 7 int a[maxn],sum[maxn]; 8 void Init() 9 { 10 for(int i=1;i<=n;i++) 11 scanf("%d",&a[i]); 12 memset(sum,0,sizeof(sum)); 13 } 14 void Solve() 15 { 16 int q,L,R,P,l,r; 17 for(int i=0;i<M;i++) 18 { 19 scanf("%d%d%d%d",&q,&L,&R,&P); 20 if(q==1) 21 { 22 sum[L] -= P; 23 sum[R+1] += P; 24 } 25 else 26 { 27 sum[L] += P; 28 sum[R+1] -= P; 29 } 30 } 31 scanf("%d%d",&l,&r); 32 long long ans = 0; 33 long long res = 0; 34 for(int i=1;i<=r;i++) 35 { 36 res += sum[i]; 37 if(i>=l) ans += res + a[i]; 38 } 39 printf("%lld ",ans); 40 } 41 int main() 42 { 43 while(scanf("%d%d",&n,&M)!=EOF) 44 { 45 Init(); 46 Solve(); 47 } 48 return 0; 49 }