BZOJ 2223: [Coci 2009]PATULJCI
阿新 • • 發佈:2018-12-02
因為給了上限,言外之意演算法與資料的上限有關,猜測是陣列,但想一想不可能,所以應該是權值線段樹
綜合一下,猜測應該是區間第K大,也就是主席樹了
最暴力的做法:每次詢問排序後檢視是否有連續超過的數相同
Q:為什麼要是超過的數相同呢?為什麼不能在給一個數據呢?
A:這是區間的一半,排序後如果存在則相同的數必須為中位數,證明略
所以結論與之前的猜想一結合,就是求區間的中位數的個數是否超過,
這與權值線段樹上一個點的值就是下標的個數的思想完全匹配,所以就是一顆主席樹
#include<cstdio> #include<iostream> using namespace std; const int N=4500000,M=3e5+5;; int n,m,T,ans,rt[M]; struct A { int lc[N],rc[N],c[N],cnt; void add(int &p,int l,int r,int x) { lc[++cnt]=lc[p],rc[cnt]=rc[p],c[cnt]=c[p]+1,p=cnt; if(l==r) return; int mid=l+r>>1; if(mid>=x) add(lc[p],l,mid,x); else add(rc[p],mid+1,r,x); } int kth(int p1,int p2,int l,int r,int k,int bz) { if(l==r) return c[p2]-c[p1]>bz?l:0; //判斷是否>r-l+1>>1,bz表示標準 int mid=l+r>>1,xx=c[lc[p2]]-c[lc[p1]]; if(xx>=k) return kth(lc[p1],lc[p2],l,mid,k,bz); return kth(rc[p1],rc[p2],mid+1,r,k-xx,bz); } }tree; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); rt[i]=rt[i-1],tree.add(rt[i],1,m,x); } //建樹 scanf("%d",&T); while(T--) { int l,r; scanf("%d%d",&l,&r); ans=tree.kth(rt[l-1],rt[r],1,m,r-l+2>>1,r-l+1>>1); //查詢中位數 if(!ans) puts("no"); else printf("yes %d\n",ans); } return 0; }