2020-2021 ACM-ICPC Brazil Subregional Programming Contest M - Machine Gun

题目链接

敌人 ( x , y ) (x,y) (x,y)能被 ( x m , y m ) (x_m,y_m) (xm,ym)打中当且仅当:
y m − x − x m 2 ≤ y ≤ y m + x − x m 2 y_m- \frac{x-x_m}{2}\leq y\leq y_m+\frac{x-x_m}{2} ym2xxmyym+2xxm
我们化简一下这个不等式, x , y x,y x,y放一边, x m , y m x_m,y_m xm,ym放一边:
{    2 y − x ≤ 2 y m − x m − 2 y − x ≤ − 2 y m − x m \begin{cases} ~~2y-x\leq2y_m-x_m\\ -2y-x\leq-2y_m-x_m\\ \end{cases} {  2yx2ymxm2yx2ymxm
好了,那么显然就是一个二维偏序的问题。
那么关键就在于如何快速的求出所有点。

可以在维护val(离散化后 2 y − x 2y-x 2yx的个数)个桶,每个桶里面装点的标号和 − 2 y − x -2y-x 2yx,用bit或者线段树找到所有的合法点即可。

树状数组和线段树的写法本质都是一样的:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;

const int mod=1e9+7;
int add(int x,int y){
  x+=y;
  if(x>=mod)x-=mod;
  if(x<0)x+=mod;
  return x;
}
int mul(int x,int y){
  return 1ll*x*y%mod;
}
int sub(int x,int y){
  x=x+mod-y;
  if(x>=mod)x-=mod;
  return x;
}
//mod_int


int n,q;
vector<LL>dx,dy;
pair<LL,LL>po[N];
struct bit{
  vector<pair<int,int>>t[N];
  void Add(int x,int y,int i){
    for(;x<N;x+=x&-x)t[x].emplace_back(y,i);
  }
  int get(int x,int y){
    vector<int>v;
    for(;x;x-=x&-x){
      for(auto k:t[x]){
        if(k.fi<y){
          v.pb(k.se);
        }else break;
      }
    }
    sort(v.begin(),v.end());
    int ans=0,pop=5782344,now=1;
    for(auto k:v){
      ans=add(ans,mul(now,k));
      now=mul(now,pop);
    }
    return ans;
  }
}T;
int main() {
  ios::sync_with_stdio(false);
  cin>>n>>q;
  for(int i=1;i<=n;i++){
    LL x,y;
    cin>>x>>y;
    LL xx=-x-2*y,yy=-x+2*y;
    dx.pb(xx);
    dy.pb(yy);
    po[i]={xx,yy};
  }
  sort(dx.begin(),dx.end());
  sort(dy.begin(),dy.end());
  dx.erase(unique(dx.begin(),dx.end()),dx.end());
  dy.erase(unique(dy.begin(),dy.end()),dy.end());
  for(int i=1;i<=n;i++){
    po[i].fi=lower_bound(dx.begin(),dx.end(),po[i].fi)-dx.begin();
    po[i].se=lower_bound(dy.begin(),dy.end(),po[i].se)-dy.begin();
    T.Add(po[i].fi+1,po[i].se,i);
  }
  for(int i=0;i<=dx.size();i++){
    sort(T.t[i].begin(),T.t[i].end());
  }
  int last=0;
  for(int i=1;i<=q;i++){
    LL x,y;
    cin>>x>>y;
    x=-1-add(last,x);
    y=add(last,y);
    LL xx=-x-2ll*y,yy=-x+2ll*y;
    int dl=upper_bound(dx.begin(),dx.end(),xx)-dx.begin();
    int dr=upper_bound(dy.begin(),dy.end(),yy)-dy.begin();
    cout<<(last=T.get(dl,dr))<<'\n';
  }
  return 0;
}
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;

const int mod=1e9+7;
int add(int x,int y){
  x+=y;
  if(x>=mod)x-=mod;
  if(x<0)x+=mod;
  return x;
}
int mul(int x,int y){
  return 1ll*x*y%mod;
}
int sub(int x,int y){
  x=x+mod-y;
  if(x>=mod)x-=mod;
  return x;
}
//mod_int


int n,q;
vector<LL>dx,dy;
pair<LL,LL>po[N];
struct uzi{
  int x,y,pos;
  bool operator <(const uzi & t)const{
    return x<t.x;
  }
}p[N];
vector<pair<int,int>>t[N<<2];
int T[N];
#define mid (l+r>>1)
int cnt;
#define ls o<<1
#define rs o<<1|1
void add(int o,int l,int r,int x,int y,int pos){
  t[o].emplace_back(y,pos);
  if(l==r)return;
  if(x<=mid)add(ls,l,mid,x,y,pos);
  else add(rs,mid+1,r,x,y,pos);
}
void build(int o,int l,int r){
  sort(t[o].begin(),t[o].end());
  if(l==r)return;
  build(ls,l,mid);
  build(rs,mid+1,r);
}
vector<int>cur;
void get(int o,int l,int r,int x,int y,int dx){
  if(l>=x&&r<=y){
    for(auto k:t[o]){
      if(k.fi<=dx)cur.emplace_back(k.se);
      else break;
    }
    return;
  }
  if(x<=mid)get(ls, l , mid,x,y ,dx);
  if(y>mid)get(rs,mid+1,r,x,y,dx);
}
int val;
int get_ans(int x,int y){
  cur.clear();
  get(1,0,val,1,x,y);
  sort(cur.begin(),cur.end());
  int ans=0,base=5782344,now=1;
  for(auto k:cur){
    ans=add(ans,mul(k,now));
    now=mul(now,base);
  }
  return ans;
}
int main() {
  ios::sync_with_stdio(false);
  cin>>n>>q;
  for(int i=1;i<=n;i++){
    LL x,y;
    cin>>x>>y;
    LL xx=-x-2*y,yy=-x+2*y;
    dx.pb(xx);
    dy.pb(yy);
    po[i]={xx,yy};
  }
  sort(dx.begin(),dx.end());
  sort(dy.begin(),dy.end());
  dx.erase(unique(dx.begin(),dx.end()),dx.end());
  dy.erase(unique(dy.begin(),dy.end()),dy.end());
  for(int i=1;i<=n;i++){
    po[i].fi=lower_bound(dx.begin(),dx.end(),po[i].fi)-dx.begin();
    po[i].se=lower_bound(dy.begin(),dy.end(),po[i].se)-dy.begin();
    p[i]={(int)po[i].fi+1,(int)po[i].se+1,i};
  }
  sort(p+1,p+1+n);
  val=dx.size();
  for(int i=1;i<=n;i++){
    add(1, 0, val, p[i].x, p[i].y, p[i].pos);
  }
  build(1,0,val);
  int last=0;
  auto find=[&](int x){
    int l=1,r=n,ok=0;
    while(l<=r){
      if(p[mid].x<=x)ok=mid,l=mid+1;
      else r=mid-1;
    }
    return ok;
  };
  for(int i=1;i<=q;i++){
    LL x,y;
    cin>>x>>y;
    x=-1-add(last,x);
    y=add(last,y);
    LL xx=-x-2ll*y,yy=-x+2ll*y;
    int dl=upper_bound(dx.begin(),dx.end(),xx)-dx.begin();
    int dr=upper_bound(dy.begin(),dy.end(),yy)-dy.begin();
    cout<<(last=get_ans(dl,dr))<<'\n';
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值