BZOJ 2223: [Coci 2009]PATULJCI

看题面戳我

因为给了上限,言外之意算法与数据的上限有关,猜测是数组,但想一想不可能,所以应该是权值线段树

综合一下,猜测应该是区间第K大,也就是主席树了

最暴力的做法:每次询问排序后查看是否有连续超过\frac{r-l+1}{2}的数相同

Q:为什么要是超过\frac{r-l+1}{2}的数相同呢?为什么不能在给一个数据呢?

A:这是区间的一半,排序后如果存在则相同的数必须为中位数,证明略

所以结论与之前的猜想一结合,就是求区间的中位数的个数是否超过\frac{r-l+1}{2}

这与权值线段树上一个点的值就是下标的个数的思想完全匹配,所以就是一颗主席树

#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;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/84481060
今日推荐