CodeForces - 817E Choosing The Commander (01字典树)

E. Choosing The Commander
time limit per test 2 seconds
memory limit per test 256 megabytes
input standard input
output standard output
As you might remember from the previous round, Vova is currently playing a strategic game known as Rage of Empires.

Vova managed to build a large army, but forgot about the main person in the army - the commander. So he tries to hire a commander, and he wants to choose the person who will be respected by warriors.

Each warrior is represented by his personality — an integer number pi. Each commander has two characteristics — his personality pjand leadership lj (both are integer numbers). Warrior i respects commander j only if  ( is the bitwise excluding OR ofx and y).

Initially Vova's army is empty. There are three different types of events that can happen with the army:

1 pi — one warrior with personality pi joins Vova's army;
2 pi — one warrior with personality pi leaves Vova's army;
3 pi li — Vova tries to hire a commander with personality pi and leadership li.
For each event of the third type Vova wants to know how many warriors (counting only those who joined the army and haven't left yet)respect the commander he tries to hire.

Input
The first line contains one integer q (1 ≤ q ≤ 100000) — the number of events.

Then q lines follow. Each line describes the event:

1 pi (1 ≤ pi ≤ 108) — one warrior with personality pi joins Vova's army;
2 pi (1 ≤ pi ≤ 108) — one warrior with personality pi leaves Vova's army (it is guaranteed that there is at least one such warrior in Vova's army by this moment);
3 pi li (1 ≤ pi, li ≤ 108) — Vova tries to hire a commander with personality pi and leadership li. There is at least one event of this type.
Output
For each event of the third type print one integer — the number of warriors who respect the commander Vova tries to hire in the event.

Example
input
5
1 3
1 4
3 6 3
2 4
3 6 3
output
1
0
Note
In the example the army consists of two warriors with personalities 3 and 4 after first two events. Then Vova tries to hire a commander with personality 6 and leadership 3, and only one warrior respects him (, and 2 < 3, but , and 5 ≥ 3). Then warrior with personality 4 leaves, and when Vova tries to hire that commander again, there are no warriors who respect him.
 

题意:

n个操作,三种情况:

1. 加入一个数值为p[i]的士兵

2.  删除一个数值为p[i]的士兵

3. 如果让一个数值为L和P的将军,询问有多少个士兵尊敬他。

一个士兵尊重这个将军,当且仅当pi异或P<L  ,

分析:

肯定可以想到将每一个数的二进制插入字典树。

增加和删除都是常规操作,关键是询问

询问的时候,将军的P值也从二进制的高位到低位遍历,

如果P在这一位为1,

L在这一位为:1,如果这一位为1的士兵,1^1=0,则下面的那些士兵肯定尊重他,直接累加,接下来就找结点为0

L在这一位为:0,如果这一位为0的士兵,1^0=1,则下面的那些士兵肯定不尊重他,直接忽略,接下来就找结点为1的。

其他照此分析就行

接下来你用数组的话就多尝试,mle和RE徘徊,还是动态开点好

#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 10000+5

typedef long long ll;
 
const int maxnode=1500000+100;//预计字典树最大节点数目
const int sigma_size=35;       //每个节点的最多儿子数
struct Trie
{
    int ch[maxnode][sigma_size];//ch[i][j]==k表示第i个节点的第j个儿子是节点k
    int val[maxnode];//val[i]==x表示第i个节点的权值为x
    int sum[maxnode];//sum[i]==x表示第i个节点的次数为x,便于删除
    int sz;//字典树一共有sz个节点,从0到sz-1标号
 
    //初始化
    void clear()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));//ch值为0表示没有儿子
        memset(sum,0,sizeof(sum));
    }
 
    //在字典树中插入单词s,但是如果已经存在s单词会重复插入且覆盖权值
    //所以insert前需要判断一下是否已经存在s单词了
    void insert(int num)
    { 
		int u=0;
        for(int i=31;i>=0;i--)///建立字典树
        {
            int id=((num>>i)&1);
            if(ch[u][id]==0)//无该儿子
            {
                ch[u][id]=sz;
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz++]=0;
            }
            u=ch[u][id];
            sum[u]++;
        }
        //val[u]=n;
    }
    int find3(int num1,int num2)
    {
    	int u=0;
    	int ans=0;
    	for(int i=31;i>=0;i--)
		{
			int t1=((num1>>i)&1);
			int t2=((num2>>i)&1);
			
			if(t1)
			{
				if(t2)
				{
					if(ch[u][1])
					ans+=sum[ch[u][1]];
					u=ch[u][0] ;
				}	
				else
				{
					u=ch[u][1];
				}
			}
			else
			{
				if(t2)
				{
					if(ch[u][0])
						ans+=sum[ch[u][0]];
					u=ch[u][1];
				}
				else
					u=ch[u][0];
			}
			if(u==0) break;
		}
		return ans;
    }
    void del(int num,int cnt) 
    {
		int u=0;
	    for(int i=31;i>=0;i--)
	    {
		   int id=((num>>i)&1);
		   if(ch[u][id]==0)
			      return ;
		   u=ch[u][id];
		   sum[u]-=cnt;
	    }
    }
};
Trie trie;
int main()
{
	int n;
	scanf("%d",&n);	  
	trie.clear();
    for(int i=1;i<=n;i++)
	{
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			int x;
			scanf("%d",&x);
			trie.insert(x);
		}
		else if(op==2)
		{
			int x;
			scanf("%d",&x);
			trie.del(x,1);
		}
		else
		{
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%d\n",trie.find3(x,y));
		}
	}
    return 0;
}

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#define rt return
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;

struct node
{
    int num;
    node *Next[2];
    node()
    {
        num=0;
        Next[0]=Next[1]=nullptr;
    }
};

void Add(node *head , int num)
{
    node *p=head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k]== nullptr)
        {
            node *q =new node();
            p->Next[k]= q;
        }
        p = p->Next[k];
        p->num++;
    }
//    p->num=num;
}
void Del(node *head ,int num)
{
    node *p=head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k]==NULL)
        {
            node * q=new node();
            p->Next[k] = q;
        }
        p = p->Next[k];
        p->num--;
    }

}
int Find(node *head, int num)
{
    node *p = head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k^1]!=NULL)
        {
             p = p->Next[k^1];

        }else
        {
            p = p->Next[k];
        }
    }
    return p->num;
}
void query(node * root,int x,int y)
{
    node *p = root;
    int res=0;
    for(int i=31;i>=0;--i)
    {
        int tx=(x&(1<<i));
        int tl=(y&(1<<i));
        if(tx)
        {
            if(tl)
            {
                if(p->Next[1])
                    res+=p->Next[1]->num;
                p=p->Next[0];
            }else
            {
                p=p->Next[1];
            }
        }else
        {
            if(tl)
            {
                if(p->Next[0])
                    res+=p->Next[0]->num;
                p=p->Next[1];
            }else
            {

                p=p->Next[0];
            }
        }
        if(p==nullptr)
            break;//
    }
    printf("%d\n",res);
}
int n;
int main()
{
    gg(n);
    node *head = new node();
    repd(i,1,n)
    {
        int op,x,y;
        gg(op);
        if(op==1)
        {
            gg(x);
            Add(head,x);
        }else if(op==2)
        {
            gg(x);
            Del(head,x);
        }else
        {
            gg(x),gg(y);
            query(head,x,y);
        }
    }
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值