西安邀请赛2021J Reverse(Trie)


题意

有两种操作
操作0:大于k的数字x,然后找到x与k第一次不相等的位数然后反转后面
操作1 查询[l,r]的个数

输入
1
6 3
1 2 3 4 5 5
1 3 6
0 3
1 3 6
输出
4
3
思路

翻转操作用tg标记一下,懒标记,每次统计跑一遍trie树

代码
/*made in mrd*/
#include
using namespace std;
const int N=2e5+10;
#define int long long
#define mem(a,b) memset(a,b,sizeof a)
#define fi first
#define se second
#define pii pair
int tr[200010*32][2],nn,siz[200010*32];
int dex;
bool tg[200010*32];
void ad(int x)
{
    int curr=0;
    
    for(int i=31;i>=0;i--)
    {
    int g=(x>>i)&1;
    if(tr[curr][g]==0){
        tr[curr][g]=++dex;
        tr[dex][0]=tr[dex][1]=siz[dex]=0;
        tg[dex]=0;
        
    }
   ++siz[curr];
    curr=tr[curr][g];
    }
    ++siz[curr];
}
void pd(int x)
{
    if(!tg[x]) return ;
    swap(tr[x][0],tr[x][1]);
    tg[x]=0;
    if(tr[x][0]) tg[tr[x][0]]^=1;
    if(tr[x][1]) tg[tr[x][1]]^=1;

}
void mdf(int x,int dep,int k)
{
    if(dep==-1||(x==0&dep!=31)) return ;
    pd(x);
    int g=(k>>dep)&1;
    if(g) {
        mdf(tr[x][1],dep-1,k);
        return ;
    }
    if(tr[x][1]) tg[tr[x][1]]^=1;
    mdf(tr[x][0],dep-1,k);
}
int calc(int x,int dep,int k)
{
    if(dep==-1||x==0&&dep!=31) return (x==0)?0:siz[x];
    pd(x);
    int g=(k>>dep)&1;  
    if(g) return (tr[x][0]==0?0:siz[tr[x][0]])+calc(tr[x][1],dep-1,k);
    return calc(tr[x][0],dep-1,k);
}
void print(int x,int dep,int curr)
{
    if(dep==-1)
    {
        for(int i=0;i>t;
    while(t--)
    {
        cin>>n>>m;
    tr[0][0]=tr[0][1]=siz[0]=0;
    tg[0]=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        ad(x);
    }
    print(0,31,0);
    int opt,x,y;
    while(m--)
    {
        cin>>opt>>x;
        if(opt==1) {
            cin>>y;
            cout<