zoukankan      html  css  js  c++  java
  • BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块

    Description

    Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
    对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
    为了方便,我们规定妹子们的美丽度全都在[1,n]中。
    给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl...sr中,权值∈[a,b]的权值的种类数。

    Input

    第一行包括两个整数n,m(1<=n<=100000,1<=m<=1000000),表示数列s中的元素数和询问数。
    第二行包括n个整数s1...sn(1<=si<=n)。
    接下来m行,每行包括4个整数l,r,a,b(1<=l<=r<=n,1<=a<=b<=n),意义见题目描述。
    保证涉及的所有数在C++的int内。
    保证输入合法。

    Output

    对每个询问,单独输出一行,表示sl...sr中权值∈[a,b]的权值的种类数。

    Sample Input

    10 10
    4 4 5 1 4 1 5 1 2 1
    5 9 1 2
    3 4 7 9
    4 4 2 5
    2 3 4 7
    5 10 4 4
    3 9 1 1
    1 4 5 9
    8 9 3 3
    2 2 1 6
    8 9 1 4

    Sample Output

    2
    0
    0
    2
    1
    1
    1
    0
    1
    2
     
     
    题意概述:给出一个序列,每次询问问序列区间[L,R]中的元素里权值在[a,b]中的不同元素种类数。
    总的一句话:所有可以用O(1)时间(总之就是代价很小)把区间[l,r]的询问转化到区间[l+1,r],[l,r-1]的询问的可离线问题都可以用莫队干掉!
    观察这个问题,可以发现如果你维护一个维护元素的数据结构,那么显然可以在你移动区间左右指针的时候做到快速修改答案,这正符合了莫队算法的用途。
    使用分块来做这个维护元素的数据结构,因为它支持O(1)修改啊!每一次查询的时候时间复杂度和移动指针的时间代价是几乎相同的。
     
    时间复杂度O((2N+M)*sqrt(N))
     
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 const int MAXN=100005;
     14 const int MAXQ=1000005;
     15 const int size=205;
     16 
     17 int N,M,S[MAXN],ans[MAXQ];
     18 struct que{
     19     int id,l,r,a,b;
     20     friend bool operator < (que a,que b){
     21         return a.l/size<b.l/size||a.l/size==b.l/size&&a.r<b.r;
     22     }
     23 }q[MAXQ];
     24 struct BLOCK{
     25     static const int maxn=100005;
     26     static const int SIZE=500;
     27     static const int maxm=205;
     28     int c[maxn],kind[maxm],lef[maxm],rig[maxm],cnt,belong[maxn];
     29     BLOCK(){ cnt=1; }
     30     void build(int n){
     31         int p=1;
     32         while(p+SIZE<n+1){
     33             lef[cnt]=p,rig[cnt]=p+SIZE,p+=SIZE,cnt++;
     34             for(int i=lef[cnt-1];i<rig[cnt-1];i++) belong[i]=cnt-1;
     35         }
     36         lef[cnt]=p,rig[cnt]=n+1;
     37         for(int i=lef[cnt];i<rig[cnt];i++) belong[i]=cnt;
     38     }
     39     void update(int p,int v){
     40         if(c[p]&&c[p]+v==0) kind[belong[p]]--;
     41         if(!c[p]&&c[p]+v==1) kind[belong[p]]++;
     42         c[p]+=v;
     43     }
     44     int query(int L,int R){
     45         int re=0,p=L;
     46         if(belong[L]==belong[R]){
     47             for(int i=L;i<=R;i++) if(c[i]) re++;
     48             return re;
     49         }
     50         for(int i=L;i<rig[belong[L]];i++) if(c[i]) re++;
     51         for(int i=lef[belong[R]];i<=R;i++) if(c[i]) re++;
     52         for(int i=belong[L]+1;i<belong[R];i++) re+=kind[i];
     53         return re;
     54     }
     55 }block;
     56 
     57 void _scanf(int &x)
     58 {
     59     x=0;
     60     char c=getchar();
     61     while(c<'0'||c>'9') c=getchar();
     62     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     63 }
     64 int out_cnt,out[15];
     65 void _printf(int x)
     66 {
     67     out[++out_cnt]=x%10,x/=10;
     68     while(x) out[++out_cnt]=x%10,x/=10;
     69     while(out_cnt) putchar('0'+out[out_cnt--]);
     70     putchar('
    ');
     71 }
     72 void data_in()
     73 {
     74     _scanf(N);_scanf(M);
     75     for(int i=1;i<=N;i++) _scanf(S[i]);
     76     for(int i=1;i<=M;i++){
     77         _scanf(q[i].l);_scanf(q[i].r);
     78         _scanf(q[i].a);_scanf(q[i].b);
     79         q[i].id=i;
     80     }
     81 }
     82 void movep(int &i,int j,int t)
     83 {
     84     while(i<j){
     85         if(!t) block.update(S[i++],-1);
     86         else block.update(S[++i],1);
     87     } 
     88     while(i>j){
     89         if(!t) block.update(S[--i],1);
     90         else block.update(S[i--],-1);
     91     }
     92 }
     93 void work()
     94 {
     95     sort(q+1,q+M+1);
     96     block.build(N);
     97     int l=1,r=1;
     98     block.update(S[1],1);
     99     for(int i=1;i<=M;i++){
    100         movep(r,q[i].r,1);
    101         movep(l,q[i].l,0);
    102         ans[q[i].id]=block.query(q[i].a,q[i].b);
    103     }
    104     for(int i=1;i<=M;i++) _printf(ans[i]);
    105 }
    106 int main()
    107 {
    108     data_in();
    109     work();
    110     return 0;
    111 }
  • 相关阅读:
    SQL生成上百万条数据 及分页 长沙
    aspx或ashx里面多个方法 进行ajax调用 长沙
    C# IO操作,文件 文件夹 长沙
    Reperter多层嵌套 长沙
    解读WPF中事件
    WPF 神话之Binding对象二
    WPF 神话之Binding对象一
    明白就好
    导出Execl和读取Execl文件
    新加入博客园,嘿嘿
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8596952.html
Copyright © 2011-2022 走看看