题意:给一段区间的部分染色,统计染色次数。
思路:差分。刚开始我也是感觉用线段树or树状数组做毕竟建树niubility而且lowbit也niubility。但是自从那天限时训练看到bin巨用差分,分分钟就敲出来了,就感觉真尼玛niubility。。。就看了看差分。
我现在所了解的差分就是可以处理区间某段同时加或减去一个数,然后进行查询的一些题目。这题太模板,代码在最后。不过想贴的是两种处理差分的办法:
1、复杂版
int add=0;
for(int i=1;i<=n;i++){
add+=b[i];
a[i]+=(a[i-1]+add);
}
for(int i=1;i<n;i++){
printf("%d ",a[i]-a[i-1]);
}printf("%d\n",a[n]-a[n-1]);
2、简单版
for(int i=1;i<=n;i++){
a[i]+=(a[i-1]+b[i]);
}
for(int i=1;i<n;i++){
printf("%d ",a[i]);
}printf("%d\n",a[n]);
两者我对比了一下,发现前者就是多了一个中间变量add,使得a[i]数组最后存的是前缀和,即第一个点到当前点所有染色次数,如果要求当前点的染色次数,那就需要用a[i]-a[i-1]来实现。
而后者就是直接存的当前点的染色次数,不需要再用前缀和来做差求得。
个人觉得两种都有利弊,对于单点查询显然后者好,但是对于区间查询来说,用前缀和作差求区间和显然要比遍历每个节点求和要好。
这就是主要的区别吧,下面上代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
#define cl(a,b) memset(a,b,sizeof(a))
#define maxn 100005
using namespace std;
int n;
int a[maxn],b[maxn];
void init(){
for(int i=1;i<=n;i++){
a[i]=b[i]=0;
}
}
int main(){
while(scanf("%d",&n)!=EOF){
if(n==0) break;
init();
for(int i=1;i<=n;i++){
int l,r;
scanf("%d%d",&l,&r);
b[l]++;
b[r+1]--;
}
//————————————方法一
int add=0;
for(int i=1;i<=n;i++){
add+=b[i];
a[i]+=(a[i-1]+add);
}
for(int i=1;i<n;i++){
printf("%d ",a[i]-a[i-1]);
}printf("%d\n",a[n]-a[n-1]);
/*————————————方法二
for(int i=1;i<=n;i++){
a[i]+=(a[i-1]+b[i]);
}
for(int i=1;i<n;i++){
printf("%d ",a[i]);
}printf("%d\n",a[n]);
*/
}
return 0;
}