[bzoj4571][主席樹]美味
阿新 • • 發佈:2018-12-09
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其實也就是一個簡單的主席樹 設且能使得
最大 從高到低位貪心,設列舉到了第i位 如果第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;
}