[靜態主席樹]Couriers
阿新 • • 發佈:2018-12-27
題目描述
給一個長度為n的序列a。1≤a[i]≤n。m組詢問,每次詢問一個區間[l,r],是否存在一個數在[l,r]中出現的次數大於(r-l+1)/2。如果存在,輸出這個數,否則輸出0。
輸入
第一行兩個數n,m(n,m≤500000)。第二行n個數,a[i]。
接下來m行,每行兩個數l,r,表示詢問[l,r]這個區間。
輸出
m行,每行對應一個答案。
樣例輸入
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
樣例輸出
1 0 3 0 4
思路:建立可持久化權值線段樹
AC程式碼:
#include <iostream> #include<cstdio> using namespace std; int x,n,m; int ls[10000010],rs[10000010],num[10000010],tot=0; int tree[500010]; inline void update(int pre,int& cur,int l,int r,int v){ cur=++tot; num[cur]=num[pre]+1; if(l==r) return; ls[cur]=ls[pre],rs[cur]=rs[pre];int m=(l+r)>>1; if(v<=m) update(ls[pre],ls[cur],l,m,v); else update(rs[pre],rs[cur],m+1,r,v); } int ask(int ltree,int rtree,int k){ int l=1,r=n; while(l<r){ int m=(l+r)>>1; if(num[ls[rtree]]-num[ls[ltree]]>=k){ ltree=ls[ltree],rtree=ls[rtree]; r=m; } else if(num[rs[rtree]]-num[rs[ltree]]>=k){//區間內只可能有1個數出現次數超過一半 ltree=rs[ltree],rtree=rs[rtree]; l=m+1; } else return 0; } return l; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&x); update(tree[i-1],tree[i],1,n,x); } while(m--){ int l,r;scanf("%d%d",&l,&r); int ans=ask(tree[l-1],tree[r],(r-l+1)/2+1); printf("%d\n",ans); } return 0; }