一维差分

  比赛时遇见了个二维差分,很可惜没看出来,还想用线段树维护,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 } 
牛客也很牛

 

posted @ 2019-04-20 22:15  新之守护者  阅读(751)  评论(0编辑  收藏  举报