K-query SPOJ - KQUERY 离线 线段树/树状数组 区间大于K的个数

题意:

  给一个数列,一些询问,问你区间$[l.r]$大于$K$的个数

题解:

  又一个"人尽皆知傻逼题"?

  我们用一个01序列表示当前询问时,该位置的数字是否对答案有贡献,

  显然,对于询问$(l,r,k)$整个区间只有大于$k$的数字对答案有贡献,

  那么离线思路就有了

  按k排序询问,排序数字,遍历所有询问,对于每次询问$(l,r,k)$,把所有大于K的数字插进去...

  复杂度O$(nlog(n)+klog(k))$

bit

#include <bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pp pair<int,int>
#define rep(ii,a,b) for(int ii=a;ii<=b;ii++)
#define per(ii,a,b) for(int ii=a;ii>=b;ii--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e6*4+10;
const int INF=0x3f3f3f3f;
int casn,n,m,k;
#define lb(x) x&-x
ll bit[maxn],num[maxn];
void update(int pos,int x){while(pos<=n) bit[pos]+=x,pos+=lb(pos);}
ll sum(int pos){
    ll ans=0;
    while(pos)ans+=bit[pos],pos-=lb(pos);
    return ans;
}
ll query(int a,int b){return sum(b)-sum(a-1);}
struct quest{int l,r,k,id;}ask[maxn];
int cmp1(quest a,quest b){
	return a.k<b.k;
}
int cmp(int a,int b){
    return num[a]<num[b];
}
map<ll,int>pos;
ll ans[maxn];
int rk[maxn];
int main(){
//#define test
#ifdef test
  freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
	scanf("%d",&n);
	rep(i,1,n) scanf("%d",num+i),rk[i]=i;
	sort(rk+1,rk+1+n,cmp);
	scanf("%d",&k);
    rep(i,1,k){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        ask[i]=(quest){a,b,c,i};
    }
    sort(ask+1,ask+1+k,cmp1);
    int pos=1;
    rep(i,1,k){
        while(pos<=n&&num[rk[pos]]<=ask[i].k){
            update(rk[pos],1);
            pos++;
        }
        ans[ask[i].id]=ask[i].r-ask[i].l+1-query(ask[i].l,ask[i].r);
    }
    rep(i,1,k) printf("%d\n",ans[i]);
#ifdef test
  fclose(stdin);fclose(stdout);system("out.txt");
#endif
  return 0;
}
posted @ 2018-07-28 21:56  nervending  阅读(597)  评论(0编辑  收藏  举报