[bzoj4571][主席树]美味

针对顾客在限定范围内选择最美味菜品的问题,通过构建01Trie树和主席树实现高效查询。文章介绍了一种利用异或操作进行最优解搜索的方法,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

一家餐厅有 n 道菜,编号 1…n ,大家对第 i 道菜的评价值为 ai(1≤i≤n)。有 m 位顾客,第 i 位顾客的期 望值为
bi,而他的偏好值为 xi 。因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或 运算。第 i
位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri
道中选择。请你帮助他们找出最美味的菜。

Input

第1行,两个整数,n,m,表示菜品数和顾客数。 第2行,n个整数,a1,a2,…,an,表示每道菜的评价值。
第3至m+2行,每行4个整数,b,x,l,r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。
1≤n≤2×10^5,0≤ai,bi,xi<10^5,1≤li≤ri≤n(1≤i≤m);1≤m≤10^5

Output

输出 m 行,每行 1 个整数,ymax ,表示该位顾客选择的最美味的菜的美味值。

Sample Input

4 4

1 2 3 4

1 4 1 4

2 3 2 3

3 2 3 3

4 1 2 4

Sample Output

9

7

6

7

题解

好题啊..
如果没有加的操作就是个裸的01Tire
有加的怎么办..
考虑到01Tire其实也就是一个简单的主席树
ans=xiajans=xi∗ajansans能使得bixoransbixorans最大
从高到低位贪心,设枚举到了第i位
如果第i位是1,于是要求ans+(1<<i)ans+(1<<i)~ans+(1<<i)+(1<<i)1ans+(1<<i)+(1<<i)−1这个区间里有数
主席树搞一搞就行了..

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define MX 100005
using namespace std;
struct trnode{int lc,rc,c;}tr[20*200005];int len,rt[200005];
void add(int &now,int l,int r,int p)
{
    if(now==0)now=++len;
    tr[now].c++;
    if(l==r)return ;
    int mid=(l+r)/2;
    if(p<=mid)add(tr[now].lc,l,mid,p);
    else add(tr[now].rc,mid+1,r,p);
}
void meg(int &x,int y)
{
    if(x==0){x=y;return ;}
    if(y==0)return ;
    tr[x].c+=tr[y].c;
    meg(tr[x].lc,tr[y].lc);
    meg(tr[x].rc,tr[y].rc);
}
int findsum(int u,int v,int l,int r,int p)
{
    if(p<0)return 0;
    if(tr[u].c-tr[v].c==0)return 0;
    if(l==r)return tr[u].c-tr[v].c;
    int mid=(l+r)/2;
    if(p<=mid)return findsum(tr[u].lc,tr[v].lc,l,mid,p);
    else return tr[tr[u].lc].c-tr[tr[v].lc].c+findsum(tr[u].rc,tr[v].rc,mid+1,r,p);
}
int n,m,a[210000],b[210000],L[210000],R[210000],bin[25];
int main()
{
    bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        add(rt[i],0,MX,x);meg(rt[i],rt[i-1]);
    }
    for(int i=1;i<=m;i++)scanf("%d%d%d%d",&a[i],&b[i],&L[i],&R[i]);
    for(int i=1;i<=m;i++)
    {
        int ans=0;
        for(int j=20;j>=0;j--)
        {
            int col=a[i]&bin[j];
            int nw=(col!=0?0:bin[j]),nxt=bin[j]-1;
            int s1=findsum(rt[R[i]],rt[L[i]-1],0,MX,ans+nw+nxt-b[i]),s2=findsum(rt[R[i]],rt[L[i]-1],0,MX,ans+nw-1-b[i]);
            if(s1-s2)ans+=nw;
            else ans+=col;
        }
        printf("%d\n",a[i]^ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值