HDU6964:I love counting——题解

https://acm.hdu.edu.cn/showproblem.php?pid=6964

给定一数列,每次查询$(l,r)$,找到数列中位于该区间内的数$c$满足$a\, xor c\le b$,求这样的数的个数(要求数不能相同)。

SB题但是我不太会套路,来补一下。

显然是建Trie,然后由于求的是不同的数所以很快想到可持久化Trie+每个节点存当前子树中拥有那些数,然后空间爆炸。

此时我比赛时想的是莫队(虽然没写也不知道对不对不过大概跑不过去)。

对每个节点记录其子树所存所有的数的话,只可能是普通Trie(这样可以保证空间为$O(nlogn)$),然后问题在于如何实现查询。

显然比较从高位往低位比较,这个相信大家都会,问题在于如何去掉相同的数,做法就是记录和它相同的下一个数的位置,如果当前的数在区间中且下一个与它相同的数不在区间中,那我们就统计这个数。

不妨设查询区间为$(L,R)$,这个数的位置与与它相同的下一个数的位置所组成的二元组为$(l,r)$,则我们要满足$L\le l \le R < r$,可以用二维数点来做,即树状数组实现,对$r$进行排序,然后每次查询为$qry(R)-qry(L-1)$。

复杂度$O(nlog^2n)$。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int B=16;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct val{
    int x,y,id;
    val(){}
    val(int _x,int _y,int _id){
        x=_x;y=_y;id=_id;
    }
    bool operator <(const val &b)const{
        return x>b.x||(x==b.x&&id>b.id);
    }
};
struct node{
    int son[2];
    vector<val>v;
}tr[N*B];
int head[N],nxt[N];
int pool,rt,a[N],n,m;
void insert(int x,int k,int pos,int now){
    tr[x].v.push_back(val(nxt[pos],pos,0));
    if(now<0)return;
    bool p=k&(1<<now);
    if(!tr[x].son[p])tr[x].son[p]=++pool;
    insert(tr[x].son[p],k,pos,now-1);
}
void query(int x,int l,int r,int _a,int _b,int pos,int now){
    if(!x)return;
    if(now<0)tr[x].v.push_back(val(r,l,pos));
    bool p=_a&(1<<now),pp=_b&(1<<now);
    if(pp&&tr[x].son[p])tr[tr[x].son[p]].v.push_back(val(r,l,pos));
    query(tr[x].son[p^pp],l,r,_a,_b,pos,now-1);
}
void init(){
    rt=++pool;
}

int t[N];
inline int lowbit(int x){return x&(-x);}
void add(int x,int y){
    for(int i=x;i<=n+1;i+=lowbit(i))t[i]+=y;
}
int qry(int x){
    int res=0;
    for(int i=x;i>0;i-=lowbit(i))res+=t[i];
    return res;
}
int ans[N];
int main(){
    init();
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=n;i>=1;i--){
        if(!head[a[i]])nxt[i]=n+1;
        else nxt[i]=head[a[i]];
        head[a[i]]=i;
    }
    for(int i=1;i<=n;i++)insert(rt,a[i],i,B);
    m=read();
    for(int i=1;i<=m;i++){
        int _l=read(),_r=read(),_a=read(),_b=read();
        query(rt,_l,_r,_a,_b,i,B);
    }
    for(int i=1;i<=pool;i++){
        sort(tr[i].v.begin(),tr[i].v.end());
        for(int j=0;j<tr[i].v.size();j++){
            if(tr[i].v[j].id){
                ans[tr[i].v[j].id]+=qry(tr[i].v[j].x)-qry(tr[i].v[j].y-1);
            }else{
                add(tr[i].v[j].y,1);
            }
        }
        for(int j=0;j<tr[i].v.size();j++){
            if(!tr[i].v[j].id)add(tr[i].v[j].y,-1);
        }
    }
    for(int i=1;i<=m;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

上一篇:Oracle 用rman删除主库的归档出现RMAN-08137


下一篇:20210819 Emotional Flutter,Medium Counting,Huge Counting,字符消除2