SPOJ DQUERY D-query(主席树)

题目

Source

http://www.spoj.com/problems/DQUERY/en/

Description

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 subsequence ai, ai+1, ..., aj.

Input

Line 1: n (1 ≤ n ≤ 30000).
Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).

Output

For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line.

Sample Input

5
1 1 2 1 3
3
1 5
2 4
3 5

Sample Output

3
2
3

分析

题目说给一个序列,多次询问一个区间内不同数的个数。

离线做法很经典吧,HDU3333
主席树做法。。其实很容易往建权值线段树那边想,不过好像行不通。。

其实做法也和离线是一样的,线段树维护的是各个位置是否要存在数,记录各个数出现最右边的位置,删除之前的位置、更新当前位置,相当于把各个数字一直往右靠。

于是这样就从左往右保存了多个版本的线段树信息,查询时就拿出右端点对应版本的线段树进行区间查询。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 33333

int x,y,root[MAXN],tree[MAXN*20],lch[MAXN*20],rch[MAXN*20],N;

void update(int i,int j,int a,int &b){
    b=++N;
    if(i==j){
        tree[b]=tree[a]+y;
        return;
    }
    int mid=i+j>>1;
    lch[b]=lch[a]; rch[b]=rch[a];
    if(x<=mid) update(i,mid,lch[a],lch[b]);
    else update(mid+1,j,rch[a],rch[b]);
    tree[b]=tree[lch[b]]+tree[rch[b]];
}
int query(int i,int j,int a){
    if(x<=i && j<=y){
        return tree[a];
    }
    int mid=i+j>>1,ret=0;
    if(x<=mid) ret+=query(i,mid,lch[a]);
    if(y>mid) ret+=query(mid+1,j,rch[a]);
    return ret;
}

int a[MAXN],last[1111111];
int main(){
    int n,q;
    scanf("%d",&n);
    for(int i=1; i<=n; ++i){
        scanf("%d",&a[i]);
    }

    for(int i=1; i<=n; ++i){
        if(last[a[i]]){
            int tmp; x=last[a[i]]; y=-1;
            update(1,n,root[i-1],tmp);
            x=i; y=1;
            update(1,n,tmp,root[i]);
        }else{
            x=i; y=1;
            update(1,n,root[i-1],root[i]);
        }
        last[a[i]]=i;
    }

    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&x,&y);
        printf("%d\n",query(1,n,root[y]));
    }
    return 0;
}
时间: 2024-10-12 16:49:08

SPOJ DQUERY D-query(主席树)的相关文章

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

SPOJ DQUERY D-query (在线主席树/ 离线树状数组)

SPOJ DQUERY 题意: 给出一串数,询问[L,R]区间中有多少个不同的数 . 解法: 关键是查询到某个右端点时,使其左边出现过的数都记录在它们出现的最右位置置1,其他位置置0,然后直接统计[L,R]的区间和就行了. 在线和离线都可以做 . 话不多说,上代码 . 在线主席树 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #inc

[CF893F]Subtree Minimum Query (主席树)

题面: 传送门:http://codeforces.com/problemset/problem/893/F 题目大意:给你一颗有根树,点有权值,问你每个节点的子树中距离其不超过k的点的权值的最小值.(边权均为1,强制在线) Solution 这题很有意思. 我们一般看到这种距离不超过k的题目,第一反应一般是建以深度为下标,以dfs序为时间轴的的主席树. 很不幸,区间最小值并不能通过减去历史状态得出某个子树的状态. 所以说,这题妙在思想的转换. 考虑以dfs序为下标,以深度为时间轴建一颗主席树.

SPOJ 3267. D-query (主席树or树状数组离线)

A - D-query Time Limit:1500MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice SPOJ DQUERY Appoint description:  System Crawler  (2014-12-06) Description English Vietnamese Given a sequence of n numbers a1, a2, ..., an and

SPOJ 3267. D-query (主席树)

A - D-query Time Limit:1500MS     Memory Limit:0KB     64bit IO Format:%lld & %llu 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 nu

SPOJ - DQUERY 主席树

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32356 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 dist

SPOJ DQUERY D-query 离线+树状数组

本来是想找个主席树的题目来练一下的,这个题目虽说可以用主席树做,但是用这个方法感觉更加叼炸天 第一次做这种离线方法,所谓离线,就在把所有询问先存贮起来,预处理之后再一个一个操作 像这个题目,每个操作要求区间不同元素的个数,我盲目去查的话,某个元素在之前如果出现了,我把他算在当前区间也不好,算在之前的区间也不好,都会出错. 一个好的方法就是把区间排好序,针对某个区间在树状数组上更新以及查询相应值,这样能准确查出结果,但又不影响之后的查询 具体来说,先把区间按右端点进行排序(我一开始按左端点排,想错

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组