字典树是一颗无根树,可以是01字典树,也可以是字符串字典树。
J - Coolbits
给出n个区间,每个区间里拿出一个数,使得总体异或值最大,求最大异或值。
一个一个枚举数是不行的,时间肯定不对,于是考虑枚举二进制位数。
从高位到低位枚举的贪心是正确的,
当你枚举一个区间当前位满足1的时候,就应该把区间放缩,掰成这个位为1的区间,
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5; int n,c; ll R[N],L[N]; bool check(ll x){ c+=x; for(int i=1;i<=n;i++){ ll a=L[i],b=R[i]; if((a|x)!=a){ a+=x;a&=c; } if((b|x)!=b){ b-=x;b|=(x-1); } if(a>b)return 0; } return 1; } void work(ll x){ for(int i=1;i<=n;i++){ ll a=L[i],b=R[i]; if((a|x)!=a){ a+=x;a&=c; } if((b|x)!=b){ b-=x;b|=(x-1); } L[i]=a;R[i]=b; // if(a>b)return 0; } } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); c=0; ll ans=0; for(int i=1;i<=n;i++)scanf("%lld %lld",&L[i],&R[i]); for(int i=30;i>=0;i--){ if(check(1<<i)){ ans+=(1<<i); work((1<<i)); } } printf("%lld ",ans); } // system("pause"); return 0; }
F - F
01字典树,
给出一个序列,
每次询问x,求序列元素最大异或值,
简单字典树,直接建树查询。
#include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=1e5+5; int tot; ll val[N*32]; ll trie[N*32][2]; void insert(ll x){ int u=0; for(int i=32;i>=0;i--){ int id=(x>>i)&1; if(!trie[u][id])trie[u][id]=++tot; u=trie[u][id]; } // val[u][id]=x; val[u]=x; } ll query(ll x){ int u=0; for(int i=32;i>=0;i--){ int id=(x>>i)&1; if(trie[u][id^1])u=trie[u][id^1]; else u=trie[u][id]; } return val[u]; } int main(){ int n,m,t,kase=0; scanf("%d",&t); while(t--){ memset(trie,0,sizeof trie); tot=0; ll x; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++){scanf("%lld",&x);insert(x);} printf("Case #%d: ",++kase); while(m--){ scanf("%lld",&x); printf("%lld ",query(x)); } } // system("pause"); return 0; } // J题意:给你一个n,统计在树状数组找lowbit过程中,实际变化的量的数的和 // I题意:给你一个数,问你他可以由几个回文数相加构成,他们是什么