您的位置:首页 > 其它

【JZOJ4598】准备食物

2016-07-09 20:36 239 查看

Description

“~妖梦,我又饿了!”

魂魄妖梦身为西行寺家的专属庭师第二代兼大小姐的西行寺幽幽子的护卫,却承担了为幽幽子准备食物的任务。幽幽子是个非常贪吃的亡灵,所以妖梦经常为食物的问题所困。

现在,妖梦有n盘食物排成一排,第i盘食物有一个属性a[i]。亡灵的体质比较特殊,所以妖梦认为食物的属性很重要。妖梦会进行q次询问,每次给出两个整数r,k,她想知道有多少个区间[i,r](1≤i≤r),区间内所有食物属性值的异或大于等于k。

Solution

一开始,乱搞了一通,得出一个异或不等式,然后异或是不满足一般的不等式性质的,搞得我打完了主席树,打好了拍之后,出了个数组之后发现错了。

后来比赛还剩下40分钟的时候打完了第三题有看了一眼第二题:不是裸的字典树吗……

打了个可持久化trie成功搞了过去。

主要思路:[i,r]表示a[i] xor a[i+1] xor …… xor a[r],所以[i,r]=[1,i-1] xor [1,r],然后把数值[1,r]对trie进行xor操作,保证异或完的数≥k的方案数,在trie上如果k的二进制位是1,那么就只能异或成1,如果是0,加上异或成1的答案,在往异或成0的搜。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
#define fod(i,a,b) for(i=a;i>=b;i--)
typedef long long ll;
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m,num,p,da,root[maxn],ans;
int a[maxn],sum[maxn],er[maxn];
struct node{
int sum,son[2];
}t[maxn*32];
void build(int x,int y,int z){
int i;
fod(i,31,1){
int q=((z&er[i])>0);
t[x].sum=t[y].sum+1;
t[x].son[q^1]=t[y].son[q^1];t[x].son[q]=++num;
x=num;y=t[y].son[q];
}
t[x].sum=t[y].sum+1;
}
void find(int x,int y,int z){
int i;
fod(i,31,1){
int q=((y&er[i])>0),p=((z&er[i])>0);
if(p){
x=t[x].son[q^1];
}
else{
ans+=t[t[x].son[1^q]].sum;
x=t[x].son[q];
}
}
ans+=t[x].sum;
}
int main(){
freopen("food.in","r",stdin);
freopen("food.out","w",stdout);
scanf("%d",&n);
fo(i,1,50)er[i]=1<<(i-1);
fo(i,1,n)scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i];
build(root[0]=++num,0,0);
fo(i,1,n)build(root[i]=++num,root[i-1],sum[i]);
for(scanf("%d",&m);m;m--){
scanf("%d%d",&k,&l);
ans=0;
find(root[k-1],sum[k],l);
printf("%d\n",ans);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: