zoukankan      html  css  js  c++  java
  • 洛谷1972 HH的项链 树状数组查询区间内不同的数的数量

    题目链接:https://www.luogu.com.cn/problem/P1972

    题意大致是:给定一个序列长度为n,给出m个查询区间,要求响应是区间内不同的数的个数。为此我们考虑到树状数组的区间查询时间复杂度是O(logn),对于题目1e6的数据O(mlogn)的复杂度是能过的。所以我们考虑用离线处理的方法,先将查询区间的左右端点和编号记录下来,对右端点进行排序。这样子每次取出一个区间时能保证截止上一个区间的右端点位置的数已经更新完毕,所以进一步只需要更新上一个区间右端点到当前区间的右端点这个左开右闭区间的值即可。我们树状数组中维护一个数出现的最新位置,比如说ai出现在j位置则update(j,1)(如果ai在前面出现过就把前面的记录抹去)。

    代码如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned int ui;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 #define pf printf
     7 #define mem(a,b) memset(a,b,sizeof(a))
     8 #define prime1 1e9+7
     9 #define prime2 1e9+9
    10 #define pi 3.14159265
    11 #define scand(x) scanf("%llf",&x) 
    12 #define f(i,a,b) for(int i=a;i<=b;i++)
    13 #define scan(a) scanf("%d",&a)
    14 #define dbg(args) cout<<#args<<":"<<args<<endl;
    15 #define pb(i) push_back(i)
    16 #define ppb(x) pop_back(x)
    17 #define inf 0x3f3f3f3f
    18 #define maxn 1000010//注意数据有1e6 
    19 int n,m,t;
    20 int a[maxn],vis[maxn],c[maxn],ans[maxn];//树状数组维护一个出现的值的最新位置 
    21 struct node{
    22     int l,r;
    23     int id;
    24 }p[maxn];
    25 bool cmp(node& a,node& b)//按右端点升序排序,便于更新新加入的数值 
    26 {
    27     return a.r<b.r;
    28 }
    29 int lowbit(int x){
    30     return x&(-x);
    31 }
    32 int query(int x)
    33 {
    34     int ans=0;
    35     for(int i=x;i;i-=lowbit(i))
    36     {
    37         ans+=c[i];
    38     }
    39     return ans;
    40 }
    41 void update(int x,int C)
    42 {
    43     for(int i=x;i<=n;i+=lowbit(i))//由于位置最长是给定的n,故不用上至maxn 
    44     {
    45         c[i]+=C;
    46     }
    47 }
    48 int main()
    49 {
    50     //freopen("input.txt","r",stdin);
    51     //freopen("output.txt","w",stdout);
    52     std::ios::sync_with_stdio(false);
    53     scan(n);
    54     f(i,1,n)
    55     {
    56         scan(a[i]);
    57      } 
    58      scan(m);
    59      f(i,1,m)
    60      {
    61          scan(p[i].l);
    62          scan(p[i].r);
    63          p[i].id=i;
    64      }
    65      sort(p+1,p+m+1,cmp);//注意排序的长度是m不是n 
    66      //mem(c,0);
    67      //mem(vis,false);
    68      int pos=1;//表示区间扫描更新的最左端位置 ,是每一轮循环需要开始更新的位置 
    69      f(i,1,m)
    70      {
    71          f(j,pos,p[i].r)
    72          {
    73              if(vis[a[j]])
    74              {
    75                  update(vis[a[j]],-1);
    76                  vis[a[j]]=j;
    77                  update(j,1); 
    78              }
    79              else
    80              {
    81                  vis[a[j]]=j;
    82                  update(j,1); 
    83              }
    84          }
    85          pos=p[i].r+1;
    86          ans[p[i].id]=query(p[i].r)-query(p[i].l-1);//查询区间内不同的数的个数 
    87      }
    88      f(i,1,m)
    89      {
    90          pf("%d
    ",ans[i]);
    91      }
    92  } 
  • 相关阅读:
    eBay商家五大市场调研工具
    最新Android ADT, SDK, SDK_tool等官方下载说明
    Android——关于ListView控件的使用方法
    Auto CAD的相关问题·绘图单位
    淘宝数据分析之数据分析工具的三个需求层次
    电阻器阻值标识的相关知识
    Android软件开发之ListView 详解
    解决android模拟器划动手势时自动输入字母“c” 的问题
    争辩:关于输出大电流的移动电源给小电流的手机充电的问题
    关于C51的中断函数要注意的几个问题
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12440955.html
Copyright © 2011-2022 走看看