zoukankan      html  css  js  c++  java
  • 洛谷 P1972 [SDOI2009]HH的项链(树状数组,离线)

    传送门

    解题思路

    因为是求区间的不同种类数,所以我们用树状数组(貌似并没有什么直接联系)

    (...表示到)

    还是和原来一样,用s[i]来表示a[i-lowbit(i)]...a[i]的种类数。

    因为有一个类似于去重的操作,所以就有一个数组记录一下is[i]表示编号为i的贝壳上一次出现的地方,每一次更新结果时s[is[i]]--;s[i]++;is[i]=i。

    但是我们想,假设询问的一个区间为a...b,下一个区间为a...b-5,并且x这种贝壳在b-3,b-7都出现过(a<b-7<b-5<b-3<b),那么我们在询问a...b时使s[b-7]--;然后再询问a...b-5时就会导致答案出错(少算了一个)。(解释的不太清楚,感性理解一下)

    所以这里我们用到一个操作——离线,所谓离线,就是一次性把问题全部输入,根据一定的顺序排序(便于解题),保存好答案后再根据原顺序输出。

    怎样用程序实现离线呢?我们可以用结构体来存储数据,每一个结构体变量中有一个保存数值,另一个保存序号,全部读入后按照数值的关键字sort一遍,输出答案前按照关键字序号再sort一遍,这样就达到了目的。

    比如说这一道题:

     1 struct ques {
     2     int l,r,ans,id;
     3 } q[maxn];
     4 bool cmp1(ques a,ques b) {
     5     return a.r<b.r;
     6 }
     7 bool cmp2(ques a,ques b) {
     8     return a.id<b.id;
     9 }
    10 int main() {
    11     //读入数据
    12     sort(q+1,q+m+1,cmp1);//第一遍sort
    13     //求出答案
    14     sort(q+1,q+m+1,cmp2);//第二遍sort
    15     //输出答案
    16     return 0;
    17 }

    AC代码

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=500005;
     6 int s[maxn],n,a[maxn],m;
     7 int is[maxn*2];
     8 inline int lowbit(int x) {
     9     return x&(-x);
    10 }
    11 void insert(int id,int k) {
    12     for(int i=id; i<=n; i+=lowbit(i)) {
    13         s[i]+=k;
    14     }
    15 }
    16 int query(int id) {
    17     int res=0;
    18     for(int i=id; i>0; i-=lowbit(i)) {
    19         res+=s[i];
    20     }
    21     return res;
    22 }
    23 struct ques {
    24     int l,r,ans,id;
    25 } q[maxn];
    26 bool cmp1(ques a,ques b) {
    27     return a.r<b.r;
    28 }
    29 bool cmp2(ques a,ques b) {
    30     return a.id<b.id;
    31 }
    32 int main() {
    33     cin>>n;
    34     int cnt=1;
    35     for(int i=1; i<=n; i++) {
    36         scanf("%d",&a[i]);
    37     }
    38     cin>>m;
    39     for(int i=1; i<=m; i++) {
    40         scanf("%d%d",&q[i].l,&q[i].r);
    41         q[i].id=i;
    42     }
    43     sort(q+1,q+m+1,cmp1);
    44     for(int i=1; i<=n; i++) {
    45         if(is[a[i]]) {
    46             insert(is[a[i]],-1);
    47         }
    48         insert(i,1);
    49         is[a[i]]=i;
    50         while(q[cnt].r==i&&cnt<=m) {
    51             q[cnt].ans=query(q[cnt].r)-query(q[cnt].l-1);
    52             cnt++;
    53         }
    54     }
    55     sort(q+1,q+m+1,cmp2);
    56     for(int i=1; i<=m; i++) {
    57         printf("%d
    ",q[i].ans);
    58     }
    59     return 0;
    60 }
  • 相关阅读:
    SqlServer执行Insert命令同时判断目标表中是否存在目标数据
    javascript避免dom事件重复触发
    磁盘结构损坏且无法读取
    iframe在iphone中滚动条无效
    Rancher2.x流水线自动化部署
    微服务模块化需要的几个基础功能
    后端程序员的Vue笔记(一)
    自信从何而来
    C#异步案例一则
    Blazor入坑指南
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/11110794.html
Copyright © 2011-2022 走看看