• 【BZOJ4571】[Scoi2016]美味 主席树


    【BZOJ4571】[Scoi2016]美味

    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

    题解:由于有加法,所以可持久化Trie不能用了。但是考虑可持久化Trie的本质,可以看成是一棵只能从中间二分的可持久化权值线段树。而我们每次没有必要二分统计[l,mid]和[mid+1,r],可以直接用主席树统计[l-x,mid-x]和[mid-x+1,r-x]。这样只需要时间复杂度多一个log就能搞定了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int N=1<<18;
    const int maxn=200010;
    int n,m,tot;
    int rt[maxn];
    struct node
    {
    	int ls,rs,siz;
    }s[maxn*30];
    void insert(int x,int &y,int l,int r,int a)
    {
    	y=++tot,s[y].siz=s[x].siz+1;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a);
    }
    int query(int l,int r,int x,int y,int a,int b)
    {
    	if(a<=l&&r<=b)	return s[x].siz-s[y].siz;
    	int mid=(l+r)>>1;
    	if(b<=mid)	return query(l,mid,s[x].ls,s[y].ls,a,b);
    	if(a>mid)	return query(mid+1,r,s[x].rs,s[y].rs,a,b);
    	return query(l,mid,s[x].ls,s[y].ls,a,b)+query(mid+1,r,s[x].rs,s[y].rs,a,b);
    }
    inline int find(int l,int r,int a,int b)
    {
    	int i,j=0,d;
    	for(i=1<<18;i;i>>=1)
    	{
    		d=(b&i)>0;
    		if(d&&!query(0,N,rt[r],rt[l-1],j-a,j+i-a-1))	j+=i;
    		if(!d&&query(0,N,rt[r],rt[l-1],j+i-a,j+i+i-a-1))	j+=i;
    	}
    	return b^j;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	int i,a,b,c,d;
    	n=rd(),m=rd();
    	for(i=1;i<=n;i++)	a=rd(),insert(rt[i-1],rt[i],0,N,a);
    	for(i=1;i<=m;i++)
    	{
    		a=rd(),b=rd(),c=rd(),d=rd();
    		printf("%d
    ",find(c,d,b,a));
    	}
    	return 0;
    }//4 4  1 2 3 4  1 4 1 4  2 3 2 3  3 2 3 3  4 1 2 4
  • 相关阅读:
    HTTP客户端
    获取IP地址和域名
    SQL语句、PL/SQL块和SQL*Plus命令之间的区别
    oracle中的游标
    oracle表问题
    精简版web浏览器
    oracle的存储过程
    数据库中的视图
    第一次作业
    折半查找
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7670369.html
Copyright © 2020-2023  润新知