[分治 杂题] Codeforces Gym 101173 CERC 16 G & BZOJ 4792 Geohash Grid

先转化问题

这里写图片描述
这里写图片描述
这里写图片描述

If we lay down numbers on a single line and mark numbers within the polyline, We obtain the optimal k-approximation by removing k1 largest gaps.

我们考虑怎么求gap 我们把网格切成两半的时候也就是把值域切成了两半 我们只要递归模拟返回区间内最大最小值就可以求出所有gap

这里写图片描述

这样的gap会有很多 肯定会炸 其实我们可以证明gap的大小不会很多 是 O(nm)

这里写图片描述

我们用 2i 大小的矩形去切多边形时 每一个切对应一个gap
而因为本质不同的切是 O(m) 的 只有大概边和顶点这么多种
对于所有size 不同的gap就是 O(nm)

算法就很明显了

Finally, we’ll revise our gap-finding algorithm, not to visit both children when the split would result in two tiles that look the same with respect to intersecting with the polygon. Instead we visit only one children, but create twice as many gaps in that branch.
It can be shown that this way we’ll only visit O(nm2) states. We have to look at the polygon through the viewport at every state to determine whether to split, so we have a total complexity of O(nm3) to find all gaps.

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int M=205;

int n,m;
int x[M],y[M];
map<ll,ll> Map;
typedef map<ll,ll>::reverse_iterator ITER;

#define _y1 min(y[i],y[j])
#define _y2 max(y[i],y[j])
#define _x1 min(x[i],x[j])
#define _x2 max(x[i],x[j])

inline abcd Solve(int x1,int y1,int x2,int y2,ll v0,ll t){
  ll dx=x2-x1,dy=y2-y1,dv=(x2-x1)*(y2-y1)/2;
  int ins=0,p=0,h=0,v=0;
  for (int i=0,j=1;i<m;i++,j=(++j)%m){
    p|=x[i]>x1 && x[i]<x2 && y[i]>y1 && y[i]<y2;
    ins^=x[i]==x[j] && x[i]<=x1 && _y1<=y1 && y1<_y2;
    h|=x[i]!=x[j] && y[i]>y1 && y[i]<y2 && max(_x1,x1)<min(_x2,x2);
    v|=x[i]==x[j] && x[i]>x1 && x[i]<x2 && max(_y1,y1)<min(_y2,y2);
  }
  if (!p && !v && !h) 
    return ins?abcd(v0,v0+dx*dy-1):abcd(1LL<<40,-1LL<<40);
  abcd a,b;
  if (dx==dy){
    if (!p && h)
      a=Solve(x1,y1,(x1+x2)/2,y2,v0,t<<1),b=abcd(a.first+dv,a.second+dv);
    else
      a=Solve(x1,y1,(x1+x2)/2,y2,v0,t),b=Solve((x1+x2)/2,y1,x2,y2,v0+dv,t);
  }else{
    if (!p && v)
      a=Solve(x1,y1,x2,(y1+y2)/2,v0,t<<1),b=abcd(a.first+dv,a.second+dv);
    else
      a=Solve(x1,y1,x2,(y1+y2)/2,v0,t),b=Solve(x1,(y1+y2)/2,x2,y2,v0+dv,t);
  }
  if (a.second!=-1LL<<40 && b.first!=1LL<<40 && a.second+1<b.first)
    Map[b.first-a.second-1]+=t;
  return abcd(min(a.first,b.first),max(a.second,b.second));
}

int p;
ll val[1000005],cnt[1000005],sum[1000005];

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); for (int i=0;i<m;i++) read(x[i]),read(y[i]);
  abcd t=Solve(0,0,1<<n,1<<n,0,1);
  ll ans=t.second-t.first+1;
  for (ITER it=Map.rbegin();it!=Map.rend();it++){
    val[++p]=it->first;
    cnt[p]=cnt[p-1]+it->second;
    sum[p]=sum[p-1]+it->first*it->second;
  }
  int Q,K;
  read(Q);
  while (Q--){
    read(K); K--; int it=lower_bound(cnt+1,cnt+p+1,K)-cnt;
    printf("%lld\n",ans-(sum[it-1]+(K-cnt[it-1])*val[it]));
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值