题目描述
小J被安排一个艰巨的任务:给n面墙刷漆,n面墙是连在一起的。按照要求她要进行m个次工作,每次对[a,b]这个区间的墙刷一次漆。她想知道,她完成工作之后,每面墙被刷了多少次漆。编个程序算算吧。。
输入
第一行两个整数n和m
接下m行,每行两个整数a和b,表示小J要对[a,b]这个区间的墙进行刷漆。
输出
输出n个整数,表示每面墙被刷了多少次漆。
这道题比较考验yy能力,一般人都会先想到将刷漆的起始点和终点开两个数组存起来,然后最后再一遍扫过去,遇到开头就+1,遇到结尾就-1,小C说这种方法叫“差分”,听起来很高大上的样子。
代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int q;
int h;
};
node A[100005];
int cnt1[100005];
int cnt2[100005];
int ans=0;
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&A[i].q,&A[i].h);
cnt1[A[i].q]++;
cnt2[A[i].h]++;
}
for(int i=1;i<=n;i++){
ans=ans+cnt1[i];
printf("%d ",ans);
ans=ans-cnt2[i];
}
return 0;
}
然而还有其他的方法,“分块”。
小C说,可以举这样一个例子,学校里对于一定学号区间内的人要发作业,那么可以先将包含在一个班级中的人的作业交给他们的班主任,及维护一个整体。
代码如下:
#include<bits/stdc++.h>//刷漆 分块
using namespace std;
int n,m,a,b,len,bzr[400],cnt[100005];
int main(){
cin>>n>>m;len=sqrt(n);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
for(int j=a-1;j<=b-1;)
if(j%len==0&&j+len<=b)bzr[j/len]++,j+=len;
else cnt[j++]++;
}
for(int i=0;i<n;i++)
printf("%d ",cnt[i]+bzr[i/len]);
return 0;
}