• HDU6964:I love counting——题解


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

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

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

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

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

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

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

    不妨设查询区间为$(L,R)$,这个数的位置与与它相同的下一个数的位置所组成的二元组为$(l,r)$,则我们要满足$Lle 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
    ",ans[i]);
        }
        return 0;
    }

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

    +本文作者:luyouqi233。               +

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

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

  • 相关阅读:
    [高精度模板][Pascal]整数加、减、乘、除、开方等
    [poj2528]求最后未完全被其它线段覆盖的线段个数
    [POJ3468]线段树模板
    火车进出栈问题(强化版)
    手把手教上Getchu.com
    集合删数
    [SBT模板题]HNOI2002 营业额统计
    离散化Pascal模板
    hdu 4507 吉哥系列故事——恨7不成妻
    组合数学总结
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/15085388.html
Copyright © 2020-2023  润新知