zoukankan      html  css  js  c++  java
  • hdu 5919 主席树

    http://acm.hdu.edu.cn/showproblem.php?pid=5919

    题意: 一个数组A。。。有Q次询问,[L,R](强制在线)。。。询问区间不同数按贡献排序后组成的新数组中的n/2项是什么,贡献是指在这个区间里面最左出现的位置。

    思路:主席树套路题。。因为强制在线,所以使用主席树。。方法和主席树求区间不同数的方法是一样的,只需要扫一遍,PS。因为这里要用到最左出现位置,所以从右往左扫。这样我们得到了n个版本的线段树,每个都可以用来查询区间不同数了(和离线版本的BIT思路一样)。接下来询问第k/2其实就是类似一个静态的线段树找第k大的做法,也很简单了。。。第一次写主席树,很神奇。。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <complex>
    using namespace std;
    const int MAXN = 200010;
    const int M = MAXN * 40;
    int n,q,tot;
    int a[MAXN];
    int T[MAXN],lson[M],rson[M],c[M];
    int build(int l,int r){
        int root = tot++;
        c[root] = 0;
        if(l != r){
            int mid = (l+r)>>1;
            lson[root] = build(l,mid);
            rson[root] = build(mid+1,r);
        }
        return root;
    }
    int update(int root,int pos,int val){
        int newroot = tot++, tmp = newroot;
        c[newroot] = c[root] + val;
        int l = 1, r = n;
        while(l < r){
            int mid = (l+r)>>1;
            if(pos <= mid){
                lson[newroot] = tot++;
                rson[newroot] = rson[root];
                newroot = lson[newroot];
                root = lson[root];
                r = mid;
            }
            else{
                rson[newroot] = tot++;
                lson[newroot] = lson[root];
                newroot = rson[newroot];
                root = rson[root];
                l = mid+1;
            }
            c[newroot] = c[root] + val;
        }
        return tmp;
    }
    
    int query(int root,int pos){
        int ret = 0;
        int l = 1, r = n;
        while(pos < r){
            int mid = (l+r)>>1;
            if(pos <= mid){
                r = mid;
                root = lson[root];
            }
            else{
                ret += c[lson[root]];
                root = rson[root];
                l = mid+1;
            }
        }
        return ret + c[root];
    }
    
    int query2(int root,int k){
        int ret = 0;
        int l = 1, r = n;
        while(l < r){
            int mid = (l+r)>>1;
            if(k <= c[lson[root]]){
                r = mid;
                root = lson[root];
            }
            else{
                k-=c[lson[root]];
                root = rson[root];
                l = mid+1;
            }
            if(l==r) return l;
        }
        return r;
    }
    
    int mp[MAXN];
    int Q[MAXN];
    
    int main(){
        Q[0]=0;
        int t,cas=1;
        scanf("%d",&t);
        while(t--){
            tot = 0;
            scanf("%d%d",&n,&q);
            for(int i = 1; i <= n; i++)    scanf("%d",&a[i]);
            T[n+1] = build(1,n);
            memset(mp,0,sizeof(mp));
            for(int i = n; i>= 1; i--){
                if(mp[a[i]] == 0){
                    T[i] = update(T[i+1],i,1);
                }
                else{
                    int tmp = update(T[i+1],mp[a[i]],-1);
                    T[i] = update(tmp,i,1);
                }
                mp[a[i]] = i;
            }
            for(int i=1;i<=q;i++){
                int l,r;
                scanf("%d%d",&l,&r);
                l=(l+Q[i-1])%n+1;
                r=(r+Q[i-1])%n+1;
                if(r<l) swap(l,r);
                int sum=query(T[l],r);
                Q[i]=query2(T[l],(sum+1)/2);
            }
            printf("Case #%d:",cas++);
            for(int i=1;i<=q;i++) printf(" %d",Q[i]);
            printf("
    ");
        }
        return 0;
    }
    



  • 相关阅读:
    企业命令linux下处理实时日志生成另一个实时日志
    排序算法Java(android)安卓中的list对象排序
    项目设置一个类似HTML map标签功能的Android组件
    最大算法【Manacher模板】HDU 3068——求最长回文子串
    类实现java面向对象上:接口
    线程方法Android:异步调用详解
    输入数字实现分页功能(三层)
    对象主题设计模式读书笔记观察者模式
    网站算法石榴算法严厉打击下 网站盈利方向何在
    闭包执行JavaScript中的闭包
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672537.html
Copyright © 2011-2022 走看看