BZOJ4925(裸裸的差分)

这种大水题,我还是没有想出来,明明都知道了是差分了。。。。

好了我们来看看,先将有重叠的区间(房子)合并(反正效果都一样),这样我们就得到了多段不重叠的区间。

然后我们枚举每一个点和每一条线段,比如说我们枚举了p这个点它在x,还有两段分别在x1,y1的一条线段,很明显我们最终如果移动的位置在x1-x~y1-x之间的话这个点是会为答案做贡献的,所以我们相当于给一个数组的x1-x~y1-x这一段加上一,最后看看哪个位置值最大,因为之前的区间已经是不重叠了,所以不必担心一个点会被多次计数。

复杂度O(nm),可以过了。

下面是程序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define maxm 1009
#define maxn 10009
#define maxx 1000009
using namespace std;
struct ding{
  int l,r;
}a[maxm],c[maxm];
int cnt,b[maxn],n,m,p,ans[maxx+maxx+100],now2,now;
bool cmp(ding x,ding y)
{
  return x.l==y.l?x.r<y.r:x.l<y.l;
}
int main()
{
  //freopen("plan6.in","r",stdin);
  //freopen("plan.out","w",stdout);
  scanf("%d%d",&n,&m);
  cnt=0;
  for (int i=1;i<=n;i++) scanf("%d",&b[i]);
  for (int i=1;i<=m;i++) scanf("%d%d",&a[i].l,&a[i].r);
  sort(a+1,a+1+m,cmp);
  ding tot=a[1];
  for(int i=2;i<=m;i++)
   if (a[i].l<=tot.r) tot.r=max(tot.r,a[i].r);
   else c[++cnt]=tot,tot=a[i];
  c[++cnt]=tot;
  for (int i=0;i<=maxx+maxx;i++) ans[i]=0;
  for (int i=1;i<=n;i++)
  for (int j=1;j<=cnt;j++)
  {
      ans[c[j].l-b[i]+maxx]++;
      ans[c[j].r-b[i]+1+maxx]--;
    //cout<<ans[c[j].l-b[i]+maxx]<<" "<<ans[c[j].r-b[i]+1+maxx]<<endl;
  }
  now2=maxx;p=0;
  for (int i=1;i<=maxx+maxx;i++)
  {
   p+=ans[i];
   if (p>now)
   {
    now2=abs(i-maxx);
    now=p;
   }
   if (p==now) now2=min(abs(i-maxx),now2);
  }
  printf("%d %d",now2,now);
  return 0;
}
原文地址:https://www.cnblogs.com/2014nhc/p/7799824.html