[SCOI2016]美味(可持久化線段樹)
阿新 • • 發佈:2018-12-14
可持久化trie樹?好像和可持久化權值線段樹差不多。。
如果這題沒有那個\(x[i]\)這題就是一個裸的可持久化trie樹。
仔細想想,多了這個\(x[i]\)之後有什麼影響?
就是我們查詢區間的時候區間的兩個端點減去一個\(x[i]\)就行了。
但是這樣我們查詢的可能不是樹上的一個節點了,我們在樹上二分的時候每一次都要呼叫一次查詢的函式。
複雜度多一個\(log\)可以接受。
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int N=250000; int n,m,tot,sum[N*30],ch[N*30][2],root[N]; void build(int l,int r,int &now){ now=++tot; if(l==r)return; int mid=(l+r)>>1; build(l,mid,ch[now][0]); build(mid+1,r,ch[now][1]); } void ins(int l,int r,int x,int pre,int &now){ now=++tot; sum[now]=sum[pre]+1; if(l==r)return; int mid=(l+r)>>1; ch[now][1]=ch[pre][1]; ch[now][0]=ch[pre][0]; if(x>mid)ins(mid+1,r,x,ch[pre][1],ch[now][1]); else ins(l,mid,x,ch[pre][0],ch[now][0]); } int getsum(int l,int r,int L,int R,int pre,int now){ if(L>R)return 0; if(l==L&&r==R){ return sum[now]-sum[pre]; } int mid=(l+r)>>1; if(L>mid)return getsum(mid+1,r,L,R,ch[pre][1],ch[now][1]); else if(R<=mid)return getsum(l,mid,L,R,ch[pre][0],ch[now][0]); else return getsum(l,mid,L,mid,ch[pre][0],ch[now][0])+ getsum(mid+1,r,mid+1,R,ch[pre][1],ch[now][1]); } int check(int x,int y,int pre,int now){ int ans=0; for(int i=17;i>=0;i--){ int t=ans+((1^((x>>i)&1))<<i); if (getsum(0,99999,max(0,t-y),min(t+(1<<i)-1-y,99999),pre,now))ans=t; else ans+=((x>>i)&1)<<i; } return ans; } int read(){ int sum=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return sum*f; } int main(){ n=read();m=read(); build(0,99999,root[0]); for(int i=1;i<=n;i++){ int a=read(); ins(0,99999,a,root[i-1],root[i]); } while(m--){ int b=read(),x=read(),l=read(),r=read(); printf("%d\n",check(b,x,root[l-1],root[r])^b); } return 0; }