zoukankan      html  css  js  c++  java
  • 【bzoj3524】【Poi2014】【Couriers】可持久化线段树(主席树)水题

    这里写图片描述
    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62485671
    向大(hei)佬(e)势力学(di)习(tou)

    Description

    给一个长度为n的序列a。1≤a[i]≤n。
    m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。

    Input

    第一行两个数n,m。
    第二行n个数,a[i]。
    接下来m行,每行两个数l,r,表示询问[l,r]这个区间。

    Output

    m行,每行对应一个答案。

    Sample Input
    7 5
    1 1 3 2 3 4 3
    1 3
    1 4
    3 7
    1 7
    6 6
    Sample Output
    1
    0
    3
    0
    4

    HINT

    【数据范围】

    n,m≤500000

    一看,区间查询,询问数字出现次数……
    主席树啊

    对前缀和的每一个节点建一个值域线段树(当然不是真建完)。每次查询的时候只需看该区间数字个数的和就可以了,因为如果该区间包含答案,则该区间的个数和一定大于r-l+1

    没想到我竟已经会了主席树(水题)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N=500000+5;
    
    struct Node{
        Node *ls,*rs;
        int sum;
    }*root[N],*null,pool[N*40],*tail=pool;
    int n,m,aa;
    
    Node *newnode(){
        Node *rt=++tail;
        rt->ls=rt->rs=null;
        rt->sum=0;
        return rt;
    }
    void insert(Node *&ndn,Node *ndp,int le,int ri,int pos){
        ndn=newnode();
        ndn->sum=ndp->sum+1;
        if(le==ri) return ;
        ndn->ls=ndp->ls,ndn->rs=ndp->rs;
        int mid=(le+ri)>>1;
        if(pos<=mid) insert(ndn->ls,ndp->ls,le,mid,pos);
        else insert(ndn->rs,ndp->rs,mid+1,ri,pos);
    }
    int query(Node *ndn,Node *ndp,int le,int ri,int limit){
        if(le==ri) return le;
        int mid=(le+ri)>>1;
        int lsum=ndn->ls->sum - ndp->ls->sum;
        int rsum=ndn->rs->sum - ndp->rs->sum;
        int rt=0;
        if(lsum>limit) rt=query(ndn->ls,ndp->ls,le,mid,limit);
        if(rsum>limit) rt=query(ndn->rs,ndp->rs,mid+1,ri,limit);
        return rt;
    }
    int main(){
        null=++tail;
        null->ls=null->rs=null;
        null->sum=0;
        root[0]=null;
    
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&aa);
            insert(root[i],root[i-1],1,n,aa);
        } 
        int x,y;
        while(m--){
            scanf("%d%d",&x,&y);
            printf("%d
    ",query(root[y],root[x-1],1,n,(y-x+1)/2));
        }
        return 0;
    }
  • 相关阅读:
    链表逆序输出 ---九度1511
    java 通过ssh连接linux服务器的测试代码
    C/C++时间函数总结
    C,C++,windows api, linux api 操作文件总结
    基于大数据计算思想的分布式数据库
    手机定位的方式
    矩阵取数问题
    回文字符串
    linux shell重定向总结
    apache flink 入门
  • 原文地址:https://www.cnblogs.com/LinnBlanc/p/7763152.html
Copyright © 2011-2022 走看看