zoukankan      html  css  js  c++  java
  • 【SDOI2009】HH的项链 线段树

    题目描述

    HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

    输入输出格式

    输入格式:

    第一行:一个整数N,表示项链的长度。

    第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。

    第三行:一个整数M,表示HH 询问的个数。

    接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

    输出格式:

    M 行,每行一个整数,依次表示询问对应的答案。

    输入输出样例

    输入样例#1:
    6
    1 2 3 4 3 5
    3
    1 2
    3 5
    2 6
    
    输出样例#1:
    2
    2
    4

    数据范围:

    对于100%的数据,N <= 500000,M <= 500000。

    ---------------------------------------------------------------------------------------------------

    这个数据一看就不能暴力标记什么的水过去

    然后看到维护和询问的区间信息 所以很快想到了线段树

    关键是维护的序列是什么呢?

    我们选择维护一个1~n的序列 对每个点:为0表示此时下标表示的数不存在,为1表示此时下标表示的数存在

    我们选择离线做法,先记录下每次询问 一边处理每个值 一边查询

    将询问按照右端点排序,now记录当前访问到的询问

    记last[i]数组 表示 i上一次出现的位置(即截止目前最后出现的位置

    用一遍for循环 update贝壳的编号进入序列 即update(1,i,1); 表示现在在当前位出现

    然后将上一次出现i的位置重置为0 即 update(1,last[a[i]],0); 并记下i出现的当前新位置last[a[i]]=i;

    对于询问 每次从处理好的询问中 找出右端点和当前处理位置相同的询问 进行查询

    怎样查询呢?

    因为每一次我们只记录下了每个值最后出现的位置 以前的早已清零,所以查询一段区间中有多少的不同值就是做区间求和

    于是就变成线段树的基本操作了ovo

    注:1.注意线段树中查询操作的写法

      2.注意开够数组

    贴个代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #define N 500100
     7 #define lc p<<1
     8 #define rc p<<1|1
     9 using namespace std;
    10 int n,m;
    11 int a[N];
    12 struct node
    13 {
    14     int l,r,val;
    15 }t[N<<6];
    16 
    17 struct pu
    18 {
    19     int x,y,id,ans;
    20 }q[N];
    21 bool cmp(pu a,pu b) { return a.y<b.y; }
    22 bool cmp1(pu a,pu b) { return a.id<b.id; }
    23 
    24 void pushup(int p){
    25     t[p].val=t[lc].val+t[rc].val;
    26 }
    27 void build(int p,int l,int r)
    28 {
    29     t[p].l=l; t[p].r=r;
    30     if(l==r) return;
    31     int mid=l+r>>1;
    32     build(lc,l,mid);
    33     build(rc,mid+1,r);
    34     pushup(p);
    35 }
    36 void update(int p,int x,int v)
    37 {
    38     if(t[p].l==t[p].r)
    39     {
    40         t[p].val=v;
    41         return;
    42     }
    43     int mid=t[p].l+t[p].r>>1;
    44     if(x<=mid) update(lc,x,v);
    45     else update(rc,x,v);
    46     pushup(p);
    47 }
    48 int query(int p,int ql,int qr)
    49 {
    50     //if(t[p].l<ql||t[p].r>qr) return 0;
    51     if(ql<=t[p].l&&t[p].r<=qr)
    52         return t[p].val;
    53     int ans=0;
    54     int mid=t[p].l+t[p].r>>1;
    55     if(ql<=mid) ans+=query(lc,ql,qr);
    56     if(qr>mid) ans+=query(rc,ql,qr);
    57     return ans;
    58 }
    59 int last[2001000];
    60 int main()
    61 {
    62     scanf("%d",&n);
    63     for(int i=1;i<=n;i++)
    64         scanf("%d",&a[i]);
    65     scanf("%d",&m);
    66     for(int i=1;i<=m;i++)
    67     {
    68         scanf("%d%d",&q[i].x,&q[i].y);
    69         q[i].id=i;
    70     }
    71     build(1,1,n);
    72     int now=1;
    73     sort(q+1,q+m+1,cmp);
    74     for(int i=1;i<=n;i++)
    75     {
    76         update(1,i,1);
    77         if(last[a[i]]) update(1,last[a[i]],0);
    78         last[a[i]]=i;
    79         while(q[now].y==i)
    80         {
    81             q[now].ans=query(1,q[now].x,q[now].y);
    82             now++;
    83         }
    84     }
    85     sort(q+1,q+m+1,cmp1);
    86     for(int i=1;i<=m;i++)
    87         printf("%d
    ",q[i].ans);
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    Android简介(8H)思维导图
    Android章节练习题及答案
    付费方式选择——选项菜单的创建和使用
    Android——选项菜单的实现
    思维导图——四级词汇2
    jquery:为动态加载的元素绑定事件
    tcp/ip协议详解
    Atom实用插件
    如何让textarea不可拖拽
    移动端网站中手机号唤起拨号界面
  • 原文地址:https://www.cnblogs.com/kylara/p/9800978.html
Copyright © 2011-2022 走看看