一维差分
比赛时遇见了个二维差分,很可惜没看出来,还想用线段树维护,wtcl。痛心之余,回来补一补差分。
差分一般用来解决区间操作,而区间操作当然可以用线段树写,但相比较下,差分更好实现而且更快,不过差分只能处理离线问题,不能一边更新一边查询。
差分的思想很简单,我们要在一个区间[l,r]内都加上一个数a,那么像树状数组去区间更新一样,我们弄一个差分数组,在dif[l]处+a,在dif[r+1]处-a,这样像前缀和一样扫过l到r这个区间时,在l处开始有+a,+a对[l,r]区间产生影响,在r+1处-a变回原来的值,对r+1后面的区间没有了影响
Color the ball HDU - 1556
题目大意:n个点,n次操作,每次对一个区间涂色,最后问每个点被涂了多少次。
1 #include<cstdio> 2 const int N=100118; 3 int cov[N],l,r; 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)&&n) 8 { 9 for(int i=1;i<=n;i++) 10 cov[i]=0; 11 for(int i=1;i<=n;i++) 12 { 13 scanf("%d%d",&l,&r); 14 cov[l]++; 15 cov[r+1]--; 16 } 17 for(int i=1;i<=n;i++) 18 { 19 if(i>1) 20 printf(" "); 21 cov[i]+=cov[i-1]; 22 printf("%d",cov[i]); 23 } 24 printf("\n"); 25 } 26 return 0; 27 }
Tallest Cow POJ - 3263
题目大意:n头牛,第i处的牛最高为h有r组关系,每组一个a,b意味着a能看到b,即a和b中间的都严格低于a和b,问每个牛最高的可能高度。
我们假设每个牛一开始都是最高的高度h,那么每组a,b关系其实就是[a+1,b-1]处的牛高度都减1。
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 using namespace std; 5 const int N=11108; 6 int high[N]; 7 map<int,int> m; 8 inline void init(int n) 9 { 10 m.clear(); 11 for(int i=1;i<=n;i++) 12 high[i]=0; 13 } 14 int main() 15 { 16 int n,pos,maxh,r,a,b; 17 while(~scanf("%d%d%d%d",&n,&pos,&maxh,&r)) 18 { 19 init(n); 20 while(r--) 21 { 22 scanf("%d%d",&a,&b); 23 if(a>b) 24 swap(a,b); 25 if(b-a<=1||m[a*n+b])//map去重边 26 continue; 27 m[a*n+b]=1; 28 high[a+1]--; 29 high[b]++; 30 } 31 for(int i=1;i<=n;i++) 32 { 33 high[i]+=high[i-1]; 34 printf("%d\n",high[i]+maxh); 35 } 36 } 37 return 0; 38 }
牛客练习赛34little w and Segment Coverage
题目大意:有n个点,有m个区间,问如果去掉其中一个区间没被任意区间覆盖的点最少有多少个,已经相应的区间编号,多个符合要求的区间输出最大编号的。
先差分处理得出每个点被多少个区间覆盖,然后记录没被覆盖的点,以及维护只被覆盖一次的点的数目的前缀和,那么去掉某个区间后,没被覆盖的点就sum[r]-sum[l-1]+原先就没被覆盖的点
1 #include<cstdio> 2 const int N=1000118; 3 int cov[N],sum[N]={0},l[N],r[N]; 4 //cov记录差分值,sum表示只被一个区间覆盖的点个数的前缀和 5 int main() 6 { 7 int n,m; 8 scanf("%d%d",&n,&m); 9 for(int i=1;i<=m;i++) 10 { 11 scanf("%d%d",&l[i],&r[i]); 12 cov[l[i]]++; 13 cov[r[i]+1]--; 14 } 15 int no=0;//no记录没被区间覆盖的点 16 for(int i=1;i<=n;i++) 17 { 18 cov[i]+=cov[i-1]; 19 if(cov[i]==0) 20 no++; 21 //因为题目要求去掉一个区间后,剩余没被覆盖的点, 22 //所以统计只被一个区间覆盖的点的前缀和 23 if(cov[i]==1) 24 sum[i]=1; 25 else 26 sum[i]=0; 27 sum[i]+=sum[i-1]; 28 } 29 int id=1,len=n+1; 30 for(int i=1;i<=m;i++) 31 { 32 int dis=sum[r[i]]-sum[l[i]-1]; 33 if(dis<=len) 34 id=i,len=dis; 35 } 36 printf("%d %d\n",id,len+no); 37 return 0; 38 }
我太难了~给个三连吧,亲~~~