hdu 5919(主席樹)
阿新 • • 發佈:2018-12-09
思路:主席樹的模板題目,我們倒著插入題目就變成了,查詢區間不同數的個數k,然後查詢區間第(k+1)/2大。寫了一下午,發現初始化寫錯了,初始化的cnt應該是1,還有陣列大小要開36倍左右,我剛開始開的20倍一直tle。
#include <stdio.h> #include <string.h> #include <algorithm>; const int N = 2e5 + 15; using namespace std; struct TR{ int l,r,sum; }tree[N*36]; int rot[N]; int cnt; //普通讀入優化 void read(int &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } void build(int l,int r,int &rt,int pos,int val) { tree[cnt++]=tree[rt]; rt=cnt-1; tree[rt].sum+=val; int mid=(l+r)>>1; if(l==r) return ; if(pos<=mid) build(l,mid,tree[rt].l,pos,val); else build(mid+1,r,tree[rt].r,pos,val); return ; } int query(int L,int R,int rt,int l,int r) { if(L<=l&&R>=r) return tree[rt].sum; int mid=(l+r)>>1; int ans=0; if(L<=mid) ans+=query(L,R,tree[rt].l,l,mid); if(R>mid) ans+=query(L,R,tree[rt].r,mid+1,r); return ans; } int query1(int rt,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; int ans=tree[tree[rt].l].sum; if(ans>=k) return query1(tree[rt].l,l,mid,k); else return query1(tree[rt].r,mid+1,r,k-ans); } int a[N]; int ans[N];int pre[N]; void init(int rt) { cnt=1; ans[0]=0;memset(rot,0,sizeof(rot)); tree[rt].l=tree[rt].r=tree[rt].sum=0;memset(pre,0,sizeof(pre)); } int main() { int t;read(t);int cas=1; while(t--) { int n,q; scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) read(a[i]); init(n+1); for(int i=n;i>=1;i--) { if(pre[a[i]]) { rot[i]=rot[i+1]; build(1,n,rot[i],pre[a[i]],-1); build(1,n,rot[i],i,1); } else { rot[i]=rot[i+1]; build(1,n,rot[i],i,1); } pre[a[i]]=i; } for(int i=1;i<=q;i++) { int l,r;read(l);read(r); l=(l+ans[i-1])%n+1; r=(r+ans[i-1])%n+1; if(l>r) swap(l,r); int k=query(l,r,rot[l],1,n); k=(k+1)/2; ans[i]=query1(rot[l],1,n,k);//直接查第l顆樹的第(k+1)/2大即可。因為區間[r+1,n]的數肯定都大於等於[l,r]區間的數。 } printf("Case #%d: ",cas++); for(int i=1;i<=q;i++) { if(i!=q) printf("%d ",ans[i]); else printf("%d\n",ans[i]); } } return 0; }