01字典树专题2 NEFU 1270 智力异或(2)|| 2017icpc青岛站 热身赛 C (01字典树)

每日推荐:https://blog.csdn.net/huzhigenlaohu/article/details/52245070
https://blog.csdn.net/timeclimber/article/details/76281356
https://blog.csdn.net/qq_33997572/article/details/80308382
http://www.bubuko.com/infodetail-406594.html

更多题目:https://blog.csdn.net/timeclimber/article/details/79194495
https://blog.csdn.net/haut_ykc/article/details/76668966
https://blog.csdn.net/jibancanyang/article/details/51893807
https://www.cnblogs.com/elpsycongroo/p/6935682.html

NEFYOJ
SDUTOJ

智力异或(2)
Problem:1270
Time Limit:5000ms
Memory Limit:36665535K

Description
有一个数列包含n个正整数a[1]~a[n](1<=n<=1e5,0<=a[i]<1e9),现在有q次操作(q<1e5),每次操作是以下两种操作中的一种:
1、输入x,对这n个数分别异或x;
2、输入k,对数列中前k大个数求和;
Input
第一行为T,表示有T(T<=10)组数据。
每组数据的第一行为n和q,表示这个数列长为n,q次操作。然后输入这n个数。
接下来,每次操作输入一行两个数op(op为1或者2)和x(或者k)(0<=x<1e9,1<=k<=n),op=1表示进行操作1,op=2表示进行操作2;
Output
每次进行操作2时,输出数列中前k大个数的和;
Sample Input
1
4 3
6 7 5 4
1 3
2 2
2 4
Sample Output
13
22
Hint
Source
CJJ


#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int trie[maxn*35][3]={0};
int Num[maxn*35][32]= {0};
long long two[40];
int num[maxn*35],cnt =1;

void Trie_insert(int x)
{
    int p = 1;
    for(int i=31; i>=0; i--)
    {
        int t = (x>>i)%2;
        if(!trie[p][t])trie[p][t] = ++cnt;
        p = trie[p][t];
        num[p]++;
        for(int j=31; j>=0; j--)
        {
            Num[p][j]+=(x>>j)%2;
        }
    }

}
void init(){
   for(int i=0;i<=cnt;i++)
   {
       num[i] =0 ;
       trie[i][0] = 0;
       trie[i][1] = 0;
       for(int j=0;j<32;j++)
        Num[i][j] = 0;
   }
    cnt=1;
}
long long Trie_query(int x,int k)
{
    int p = 1;
    long long ans =0 ;
    for(int i=31; i>=0&&k; i--)
    {
        int t = (x>>i)%2;
        if(t==0)
        {
            if(trie[p][1])
            {
                if(num[trie[p][1]]<=k)
                {
                    k-=num[trie[p][1]];
                    for(int j=31; j>=0; j--)
                    {
                        int pp = (x>>j)%2;
                        if(pp==0)
                            ans+=Num[trie[p][1]][j]*two[j];
                        else
                            ans+=(num[trie[p][1]]-Num[trie[p][1]][j])*two[j];

                    }
                    p = trie[p][0];
                }
                else p = trie[p][1];
            }
            else
            p = trie[p][0];


        }
        else
        {
            int hh = trie[p][0];
          if(hh)
          {
              if(num[hh]<=k)
              {
                  k-=num[hh];
                  for(int j=31;j>=0;j--)
                  {
                      int pp  = (x>>j)%2;
                      if(pp==0)
                      {
                          ans+=Num[hh][j]*two[j];
                      }
                      else ans+=(num[hh]-Num[hh][j])*two[j];
                  }
                  p = trie[p][1];
              }
              else p = trie[p][0];
          }
          else p = trie[p][1];
        }
    }
    if(k)
    {
        for(int i=31;i>=0;i--)
        {
            int pp = (x>>i)%2;
            if((pp==0&&Num[p][i])||(pp==1&&!Num[p][i]))
            {
                ans+=two[i]*k;
            }
        }
    }
    return ans;
}
int main()
{
    two[0] = 1;
    for(int i=1;i<32;i++)two[i] = two[i-1]*2;
    //freopen("in.txt","r",stdin);
    int T,n,m,x;
    scanf("%d",&T);
    while(T--)
    {
        int temp = 0;
        scanf("%d%d",&n,&m);
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&x);
            Trie_insert(x);
        }
        for(int i=1; i<=m; i++)
        {
            int op,x;
            scanf("%d%d",&op,&x);
            if(op==1)
            {
                temp^=x;
            }
            else
            {
                printf("%lld\n",Trie_query(temp,x));
            }
        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/80807251