码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 5919 主席树(区间不同数的个数 + 区间第k大)

时间:2016-10-07 17:42:57      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:

Sequence II

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 849    Accepted Submission(s): 204


Problem Description
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,?,an There are m queries.

In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,?,ari.

We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as p(i)1,p(i)2,?,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<?<p(i)ki).

Note that ki is the number of different integers in this subsequence. You should output p(i)ki2for the i-th query.
 

 

Input
In the first line of input, there is an integer T (T2) denoting the number of test cases.

Each test case starts with two integers n (n2×105) and m (m2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,?,an,0ai2×105).

There are two integers li and ri in the following m lines.

However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to li,ri(1lin,1rin). As a result, the problem became more exciting.

We can denote the answers as ans1,ans2,?,ansm. Note that for each test case ans0=0.

You can get the correct input li,ri from what you read (we denote them as li,ri)by the following formula:
li=min{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}

ri=max{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}
 

 

Output
You should output one single line for each test case.

For each test case, output one line “Case #x: p1,p2,?,pm”, where x is the case number (starting from 1) and p1,p2,?,pm is the answer.
 

 

Sample Input
2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4
 

 

Sample Output
Case #1: 3 3 Case #2: 3 1
Hint
技术分享

 

 

/*
hdu 5919 主席树(区间不同数的个数 + 区间第k大)

problem:
给你n个数字,和m个查询.
将[l,r]之间数第一次出现的位置信息弄成一个新的数组,然后找出其中k/2大的数.(k为位置的数量)

solve:
通过主席树能够找出[l,r]之间有多少个不同的数,然后利用再用一个查询找出第k大的即可.
(都是类似与线段树的操作, T[i]存的是[1,n]的信息, 尽管说的只是[i,n] ,只是[1,i-1]的还没更新而已.  所以查询的时候出了点问题)

hhh-2016-10-07 16:48:19
*/
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <set>
#include <map>
//#define lson  i<<1
//#define rson  i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))

using namespace std;

const int maxn = 200100;
const int N = maxn * 100;


template<class T> void read(T&num)
{
    char CH;
    bool F=false;
    for(CH=getchar(); CH<‘0‘||CH>‘9‘; F= CH==‘-‘,CH=getchar());
    for(num=0; CH>=‘0‘&&CH<=‘9‘; num=num*10+CH-‘0‘,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p)
{
    if(!p)
    {
        puts("0");
        return;
    }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + ‘0‘);
    putchar(‘\n‘);
}

int lson[N],rson[N],c[N];
int a[maxn],T[maxn];
int tot,n,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
        {
            lson[newroot] = lson[root],rson[newroot] = tot++;
            newroot = rson[newroot],root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}


int query(int root,int pos)
{
    int cnt = 0;
    int l = 1,r = n;
    while(pos < r)
    {
        int mid = (l + r) >> 1;
        if(pos <= mid)
        {
            root = lson[root];
            r = mid;
        }
        else
        {
            cnt += c[lson[root]];
            root = rson[root];
            l = mid + 1;
        }
    }
    return cnt + c[root];
}


int Find(int root,int k)
{
    int l = 1,r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(l == r)
            return l;
        if(c[lson[root]] >= k)
        {
            root = lson[root];
            r = mid;
        }
        else
        {
            k -= c[lson[root]];
            root = rson[root];
            l = mid +1 ;
        }
    }
}

int main()
{
    int t,cas = 1;
//    freopen("in.txt","r",stdin);
    read(t);
    while(t--)
    {
        tot = 0;
        read(n),read(m);
        for(int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        T[n + 1] = build(1,n);
        map<int,int> mp;
        for(int i = n; i >= 1; i--)
        {
            if(mp.find(a[i]) == mp.end())
            {
                T[i] = update(T[i + 1],i,1);
            }
            else
            {
                int tp = update(T[i+1],mp[a[i]],-1);
                T[i] = update(tp,i,1);
            }
            mp[a[i]] = i;
        }
        int ans = 0;
        int l,r;
        printf("Case #%d:",cas++);
        for(int i = 1; i <= m; i++)
        {
            read(l),read(r);
//            cout << l <<" " <<r << endl;
            l = (l + ans) % n + 1;
            r = (r + ans)%n + 1;
            if(l > r)
                swap(l,r);
            int num = (query(T[l],r)+1) >> 1;
//            if(!num) num = 1;
            ans = Find(T[l],num);
            printf(" %d",ans);
        }
        printf("\n");
    }
    return 0;
}

  

hdu 5919 主席树(区间不同数的个数 + 区间第k大)

标签:

原文地址:http://www.cnblogs.com/Przz/p/5936266.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!