icpc徐州网络赛 I题,树状数组维护二维偏序问题

分析过程如下:

1.由于输入为一个排列,那么可以推算出,符合条件的点对一定是$nlogn$级别的

2.询问等价于查询$[l,r]$内有多少个$(x,y)$满足$l≤x$ 且 $y<=r$

3.我们发现,这就是一个二维偏序问题

4.更直观地,我们可以把每个满足要求的点对看做一个二维平面上的点$(x,y)$

5.那么每次查询就等于查询点$(l,r)$右下角的点的个数,离线+树状数组即可

#include<bits/stdc++.h>
#define ll long long
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;//head
const int maxn=1e5+10,maxm=4e6+10;
const ll INF=0x3f3f3f3f,mod=1e9+7;
int casn,n,m,k;
struct bit{
  ll node[maxn],n;
  inline int lb(int x) {return x&(-x);}
  void init(int _n){n=_n;fill_n(node,n+2,0);}
  inline void update(int pos,ll val){
    if(pos>0)for(int i=pos;i<=n;i+=lb(i))
      node[i]+=val;
  }
  inline ll ask(int pos){
    ll sum=0;
    if(pos>0)for(int i=pos;i;i-=lb(i))
      sum+=node[i];
    return sum;
  }
  inline ll query(int l,int r){
    return ask(r)-ask(l-1);
  }
}tree;
int a[maxn];
int pos[maxn];
struct node{
  int x,y,id;
}pt[maxm],ask[maxn];
int cmp(node a,node b){
  if(a.y==b.y) return a.x<b.x;
  return a.y<b.y;
}
int cnt;
ll ans[maxn];
int main(){IO;
  cin>>n>>m;
  rep(i,1,n) cin>>a[i];
  rep(i,1,n) pos[a[i]]=i;
  rep(i,1,n){
    for(int j=2*i;j<=n;j+=i){
      int posx=pos[i];
      int posy=pos[j];
      if(posx>posy) swap(posx,posy);
      pt[++cnt]={posx,posy,0};
    }
  }
  rep(i,1,m){
    int a,b;cin>>a>>b;
    ask[i]={a,b,i};
  }
  sort(pt+1,pt+1+cnt,cmp);
  sort(ask+1,ask+1+m,cmp);
  tree.init(n);
  int l=1;
  rep(i,1,m){
    while(l<=cnt&&pt[l].y<=ask[i].y){
      tree.update(pt[l].x,1);
      l++;
    }
    ans[ask[i].id]=tree.query(ask[i].x,n);
  }
  rep(i,1,m) cout<<ans[i]<<'\n';
}
posted @ 2019-09-07 18:35  nervending  阅读(364)  评论(0编辑  收藏  举报