ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU6964 I love counting (字典树+莫队)

2021-07-30 21:58:13  阅读:183  来源: 互联网

标签:node pp ch love int read maxn counting 莫队


题意:
给定一个长度为 n n n 的序列 c , q c,q c,q 次询问,每次给出 l , r , a , b l,r,a,b l,r,a,b求在 [ l , r ] [l,r] [l,r]中有多少种不同的值 k k k 满足 k ⊕ a ≤ b ​ . k⊕a≤b​. k⊕a≤b​.

题解:
莫队+字典树
补题的时候看到了带佬新得一种写法,即把字典树当成一颗完全二叉树去跑,不需要新建结点编号。

在 Trie 上顺着 a⊕b 走 ,为什么要跟着a⊕b走呢?
因为顺着a⊕b走也就是,顺着a⊕字典树=b走 当b=1时,就可以把c⊕a=0加入答案
若 b 当前位是 1,则所有 k⊕a 在当前位是 0 的数字都符合要求
找出字典树中与a当前为相同得值 (让其⊕后为0)

当然树状数组上套一个字典树也是一个不错得选择,先对r进行排序,然后离线询问,老套路题了。

代码:

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+10;


struct Q{
    int l,r,k,a,b;
}pp[maxn];
int n,m,k;
int pos[maxn],a[maxn],cnt[maxn];
int sum[maxn*18],ans[maxn];
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return x*f;
}

struct rule{
    bool operator()(const Q & a,const Q & b)const{
    if(pos[a.l]!=pos[b.l]) return a.l<b.l;
    if(pos[a.l]&1) return a.r<b.r;
    return a.r>b.r;
    }
};

void add(int x,int v){
    int node=1;
    sum[node]+=v;
    for(int i=17;i>=0;i--){
        node=(node<<1)+(x>>i&1);
        sum[node]+=v;
    }
}

int query(int a,int b){
    int node=1,res=0;
    //cout<<"debug"<<endl;
    for(int i=17;i>=0;i--){  
    //在 Trie 上贴着 a^b 走  也就是说贴着a^字典树=b走 当b=1时,就可以把k^a=0加入答案
        int t=(a>>i&1)^(b>>i&1);
    //若 b 当前位是 1,则所有 k^a 在当前位是 0 的数字都符合要求
        if(b>>i&1) res+=sum[(node<<1)+(t^1)];
   //找出字典树中与a当前为相同得值 (让其^后为0)
        node=(node<<1)+t;
    }
    res+=sum[node];
    return res;
}


int main() {
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);

    n=read();
    int sz=sqrt(n);
    for(int i=1;i<=n;i++){
        a[i]=read();
        pos[i]=i/sz;
    }
    int q;
    q=read();
    for(int i=1;i<=q;i++){
        pp[i].l=read();
        pp[i].r=read();
        pp[i].a=read();
        pp[i].b=read();
        pp[i].k=i;
    }
    sort(pp+1,pp+1+q,rule());
    int l=1,r=0;
    for(int i=1;i<=q;i++){
        while(pp[i].l<l){
            l--;
            if(++cnt[a[l]]==1){
                add(a[l],1);
            }
        }
        while(pp[i].r>r){
            r++;
            if(++cnt[a[r]]==1){
                add(a[r],1);
            }
        }
        while(pp[i].l>l){
            if(--cnt[a[l]]==0){
                add(a[l],-1);
            }
            l++;
        }
        while(pp[i].r<r){
            if(--cnt[a[r]]==0){
                add(a[r],-1);
            }
            r--;
        }
        ans[pp[i].k]=query(pp[i].a,pp[i].b);
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
}

标签:node,pp,ch,love,int,read,maxn,counting,莫队
来源: https://blog.csdn.net/xxxxxiao123/article/details/119256646

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有