SPOJ DQUERY 区间内不同数的个数 主席树

#include <iostream>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 30010,MAXLOG = 20;

struct ChairTree
{
    int l,r;
    int ans;
}ct[MAXN*MAXLOG];
int ctRoot[MAXN];
int ctTop;

int num[MAXN],tnum[MAXN],pre[MAXN];

int CreatNewNode()
{
    ct[ctTop].l = -1,ct[ctTop].r = -1;
    ct[ctTop].ans = 0;
    return ctTop++;
}

void InitZeroLayer(int &root,int l,int r)
{
    root = CreatNewNode();

    if(l == r)
        return ;
    int mid = (l+r)>>1;
    InitZeroLayer(ct[root].l,l,mid);
    InitZeroLayer(ct[root].r,mid+1,r);
}

int BS(int L,int R,int x)
{
    int mid;

    while(L <= R)
    {
        mid = (L+R)>>1;
        if(tnum[mid] == x)
            return mid;
        if(tnum[mid] < x)
            L = mid+1;
        else
            R = mid-1;
    }
    return -1;
}

void PushUp(int root)
{
    ct[root].ans = ct[ct[root].l].ans + ct[ct[root].r].ans;
}

void Update(int pre,int &root,int L,int R,int goal,int info)
{
    if(root == -1 || root == pre)
    {
        root = CreatNewNode();
        ct[root].ans = ct[pre].ans;
    }
    if(L == R)
    {
        ct[root].ans += info;
        return ;
    }

    int mid = (L+R)>>1;

    if(goal <= mid)
    {
        if(ct[root].r == -1)
            ct[root].r = ct[pre].r;
        Update(ct[pre].l,ct[root].l,L,mid,goal,info);
    }
    else
    {
        if(ct[root].l == -1)
            ct[root].l = ct[pre].l;
        Update(ct[pre].r,ct[root].r,mid+1,R,goal,info);
    }

    PushUp(root);
}

void InitCt(int n)
{

    memset(pre,-1,sizeof(pre));
    sort(tnum+1,tnum+n+1);
    int site,tn,i;

    for(tn = 1,i = 2;i <= n; ++i)
        if(tnum[i] != tnum[tn])
            tnum[++tn] = tnum[i];

    memset(ctRoot,-1,sizeof(ctRoot));
    ctTop = 0;
    InitZeroLayer(ctRoot[0],1,n);

    for(i = 1;i <= n; ++i)
    {
        site = BS(1,tn,num[i]);
        if(pre[site] == -1)
            Update(ctRoot[i-1],ctRoot[i],1,n,i,1);
        else
        {
            Update(ctRoot[i-1],ctRoot[i],1,n,pre[site],-1);
            Update(ctRoot[i-1],ctRoot[i],1,n,i,1);
        }
        pre[site] = i;
    }
}

int Query(int root,int goal,int L,int R)
{
    if(goal == L)
        return ct[root].ans;

    int mid = (L+R)>>1;

    if(mid+1 <= goal)
        return Query(ct[root].r,goal,mid+1,R);
    return Query(ct[root].l,goal,L,mid) + ct[ct[root].r].ans;
}

int main()
{
    int i,l,r,q,n;

    while(scanf("%d",&n) != EOF)
    {
        for(i = 1;i <= n; ++i)
        {
            scanf("%d",&num[i]);
            tnum[i] = num[i];
        }

        InitCt(n);

        scanf("%d",&q);

        while(q--)
        {
            scanf("%d %d",&l,&r);

            printf("%d\n",Query(ctRoot[r],l,1,n));
        }
    }

    return 0;
}

时间: 2024-11-10 14:34:51

SPOJ DQUERY 区间内不同数的个数 主席树的相关文章

区间内x的出现个数(主席树)

题目大概:求区间内x出现的次数 出题人yjy Description ZJK 给你一个长度为 n 的数列和 m 次询问,每次询问从第 l 个到第 r 个数中,数 x 出现了多少次.Input第一行一个整数 n,第二行 n 个整数,表示这个数列.第三行一个整数 m,表示询问数.下面 m 行,每行三个整数 l, r, x,表示询问[l, r]之间数 x 出现的次数Output对于每个询问操作,输出该询问的答案.答案之间用换行隔开,一共 m 行.Example61 1 2 3 3 181 6 13 5

hdu3709(求区间内平衡数的个数)数位dp

题意:题中平衡数的定义: 以一个位置作为平衡轴,然后左右其他数字本身大小作为重量,到平衡轴的距离作为全职,实现左右平衡(即杠杆原理平衡).然后为区间[x,y]内平衡数的个数. (0 ≤ x ≤ y ≤ 1018) 解法:数位dp.如果一个数的平衡数,那么它的平衡轴位置是确定的.原来一直尝试数位dp在dfs时候列举平衡轴的位置,后来才意识到可以提前枚举平衡轴位置,然后再dfs,这样比较好写.dp[mid][pre][wei];表示对称轴是mid,计算第pre个位置以后需要力矩大小wei的数的个数.

SPOJ 3267 D-query(离散化+主席树求区间内不同数的个数)

DQUERY - D-query #sorting #tree English Vietnamese Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

给出一个区间[a, b],计算区间内“神奇数”的个数。 神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数。 比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数。同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数。

给出一个区间[a, b],计算区间内"神奇数"的个数.神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数.比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数.同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数. 输入描述: 输入为两个整数a和b,代表[a, b]区间 (1 ≤ a ≤ b ≤ 10000). 输出描述: 输出为一个整数,表示区间内满足条件的整数个数 输入例子: 11 20 输出例子: 6 1 #in

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

Problem Description Now you are back,and have a task to do: Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s. And you have some query,each time you should calculate f(s[l...r]), s[l

HDU5172GTY&#39;s gay friends——区间查询(区间内的数互不相同)

http://acm.split.hdu.edu.cn/showproblem.php?pid=5172 官方题解 一个区间是排列只需要区间和为len(len+1)2(len为区间长度),且互不相同,对于第一个问题我们用前缀和解决,对于第二个问题,预处理每个数的上次出现位置,记它为pre,互不相同即区间中pre的最大值小于左端点,使用线段树或Sparse Table即可在O(n)/O(nlogn)的预处理后 O(logn)/O(1)回答每个询问.不过我们还有更简单的hash做法,对于[1..n]

给定区间求不同数的个数

Different Integers Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ...,

CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树

求两个数列的子列的交集 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1104 Description 给两个数列A, B,长度分别为n1, n2,保证A中每个元素互不相同,保证B中每个元素互不相同..进行Q次询问,每次查找A[l1...r1]和B[l2..r2]的交集 集合 大小是多少.. 比如 A = {1,2,3,4,5,6,7},B = {7,6,5,4,3,2,1}