• bzoj2223 [Coci 2009]PATULJCI


    2223: [Coci 2009]PATULJCI

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 1414  Solved: 612
    [Submit][Status][Discuss]

    Description

    Input

     10 3 1 2 1 2 1 2 3 2 3 3 8 1 2 1 3 1 4 1 5 2 5 2 6 6 9 7 10

    Output

    no
    yes 1
    no
    yes 1
    no
    yes 2
    no
    yes 3

    HINT

    Notice:输入第二个整数是序列中权值的范围Lim,即1<=ai(1<=i<=n)<=Lim。

    1<=Lim<=10000

    分析:

       其实这道题如果是第一次做还是有点难想出来的.它的突破口是什么呢?我们可以先查询权值在区间[L,R]内的数的出现次数是否大于(r - l + 1) / 2,是的话查询左半区间和右半区间是否分别大于.只要一个区间大于,就可以往那个子区间递归,这样不断地缩小区间大小,直到区间的L == R,就能确定那个数了.这就类似于二分找第k小的数的过程,每次判断小于当前数的数有多少个,最后不断缩小范围,或许这是求解已知排名的数是多少的通用解法吧.

       主席树的应用.

              插入操作就是普通的插入,查询操作采用步步逼近的方法,如果左区间的数的个数大于(r - l + 1) / 2,就在左区间中找,否则在右区间中找.最后直到l == r,返回l就可以了.

              应用主席树解题主要是要想到它的性质.是权值线段树,记录前缀等等.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxm = 500005;
    
    int n,q,maxn,cnt,root[maxm];
    
    struct node
    {
        int left,right,sum;
    }e[maxm * 20];
    
    void update(int x,int &y,int l,int r,int v)
    {
        e[y = ++cnt] = e[x];
        e[y].sum++;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        if (v <= mid)
            update(e[x].left,e[y].left,l,mid,v);
        else
            update(e[x].right,e[y].right,mid + 1,r,v);
    }
    
    int query(int l,int r,int x,int y,int k)
    {
        if (l == r)
            return l;
        int mid = (l + r) >> 1;
        if (e[e[y].left].sum - e[e[x].left].sum > k)
            return query(l,mid,e[x].left,e[y].left,k);
        if (e[e[y].right].sum - e[e[x].right].sum > k)
            return query(mid + 1,r,e[x].right,e[y].right,k);
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&n,&maxn);
        for (int i = 1; i <= n; i++)
        {
            int x;
            scanf("%d",&x);
            update(root[i - 1],root[i],1,maxn,x);
        }
        scanf("%d",&q);
        while (q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            int ans = query(1,maxn,root[l - 1],root[r],(r - l + 1) / 2);
            if (ans == 0)
                puts("no");
            else
                printf("yes %d
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    Ubuntu下libpcap安装
    chrome浏览器如何保存pdf
    C++文件操作
    Word2010制作饭店活动宣传单
    PPT2010制作翻牌动画
    PPT2010制作清明上河图动画
    PPT2010制作充电动画
    Java中Jar包调用命令行运行编译
    Java带包结构调用命令行运行编译
    Word2010制作简单个人简历
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8435706.html
Copyright © 2020-2023  润新知