zoukankan      html  css  js  c++  java
  • 【BZOJ 2120】数颜色【分块/莫队】

    题意

      给出n个数字和m个操作。操作有两种。1:查询区间[l,r]内不同种类得数字个数。2: 将下标为p得数字修改为v

    分析

     如果不是修改操作的话,用莫队贼简单就可以水过,但是因为带了修改就有一些麻烦了。

    分块

     开一个数组pre[i]记录上一个和第i个元素相同元素得位置。那么对于区间[l,r],当pre[i]<l的时候,ans++。完整块内就可以直接二分查找,不完整块直接暴力。修改是直接暴力修改因为它保证修改操作不会超过1000次。

        下面是代码

      

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 #include <cmath>
     6 using namespace std;
     7 const int maxn=10000+10;
     8 int a[maxn],belong[maxn],L[maxn],R[maxn],pre[maxn];
     9 int last[1000000+100],b[maxn];
    10 
    11 int n,m,cnt,block;
    12 void update(int p,int v){
    13     for(int i=1;i<=n;i++)
    14         last[a[i]]=0;
    15     a[p]=v;
    16     for(int i=1;i<=n;i++){
    17         b[i]=last[a[i]];
    18         last[a[i]]=i;
    19     }
    20     for(int i=1;i<=cnt;i++){
    21         for(int j=L[i];j<=R[i];j++)
    22             pre[j]=b[j];
    23         sort(pre+L[i],pre+R[i]+1);
    24     }
    25 }
    26 int Find(int p,int v){
    27     int res=1;
    28     int l=L[p],r=R[p];
    29     while(l<=r){
    30         int m=l+(r-l)/2;
    31         if(pre[m]<v){
    32             res=m;
    33             l=m+1;
    34         }else{
    35             r=m-1;
    36         }
    37     }
    38     return res-L[p]+1;
    39 }
    40 
    41 int query(int l,int r){
    42     int res=0;
    43     if(belong[l]==belong[r]){
    44         for(int i=l;i<=r;i++){
    45             if(b[i]<l)
    46                 res++;
    47         }
    48         return res;
    49     }
    50     for(int i=l;i<=R[belong[l]];i++)
    51         if(b[i]<l)
    52             res++;
    53 
    54     for(int i=L[belong[r]];i<=r;i++)
    55         if(b[i]<l)
    56             res++;
    57 
    58     for(int i=belong[l]+1;i<belong[r];i++){
    59         res+=Find(i,l);
    60     }
    61     return res;
    62 }
    63 
    64 int main(){
    65     scanf("%d%d",&n,&m);
    66     for(int i=1;i<=n;i++){
    67         scanf("%d",&a[i]);
    68         b[i]=last[a[i]];
    69         last[a[i]]=i;
    70     }
    71     block=sqrt(n);cnt=n/block;
    72     if(n%block)cnt++;
    73     for(int i=1;i<=n;i++)
    74         belong[i]=(i-1)/block+1;
    75     for(int i=1;i<=cnt;i++)
    76         L[i]=(i-1)*block+1,R[i]=i*block;
    77     R[cnt]=n;
    78 
    79     for(int i=1;i<=cnt;i++){
    80         for(int j=L[i];j<=R[i];j++)
    81             pre[j]=b[j];
    82         sort(pre+L[i],pre+R[i]+1);
    83     }
    84     char c;
    85     int l,r;
    86     for(int i=1;i<=m;i++){
    87         scanf(" %c",&c);
    88         if(c=='Q'){
    89             scanf("%d%d",&l,&r);
    90             printf("%d
    ",query(l,r));
    91         }else{
    92             scanf("%d%d",&l,&r);
    93             update(l,r);
    94         }
    95     }
    96 return 0;
    97 }
    View Code

    莫队

      对于莫队来说,难点就在于它带有修改操作。我们怎么来处理修改呢?我们在除了l,r指针以外再增加一个指针now,用类似l和r得方式进行维护。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <iostream>
      5 #include <cmath>
      6 
      7 using namespace std;
      8 const int maxn=10000+100;
      9 int belong[maxn],val[maxn];
     10 struct Node{
     11     int L,R,id,tim;
     12     bool operator<(const Node& rhs)const{
     13         return belong[L]==belong[rhs.L]?(belong[R]==belong[rhs.R]?tim<rhs.tim:R<rhs.R):L<rhs.L;
     14     }
     15     int ans;
     16 }ask[maxn];
     17 struct Up{
     18     int p,v,z;
     19 }up[maxn];
     20 int num1,num2;
     21 int cmp(Node a,Node b){
     22     return a.id<b.id;
     23 }
     24 int n,q;
     25 int f[1000000+100],ans,block,l,r,now;
     26 void update(int p,int addv){
     27     if(addv>0){
     28         f[val[p]]++;
     29         if(f[val[p]]==1)
     30             ans++;
     31     }else{
     32         f[val[p]]--;
     33         if(f[val[p]]==0)
     34             ans--;
     35     }
     36 }
     37 void in_time(int x){
     38     if(up[x].p>=l&&up[x].p<=r){
     39         update(up[x].p,-1);
     40     }
     41     up[x].z=val[up[x].p];
     42     val[up[x].p]=up[x].v;
     43     if(up[x].p>=l&&up[x].p<=r){
     44         update(up[x].p,1);
     45     }
     46 }
     47 void out_time(int x){
     48     if(up[x].p>=l&&up[x].p<=r)
     49         update(up[x].p,-1);
     50     val[up[x].p]=up[x].z;
     51     if(up[x].p>=l&&up[x].p<=r)
     52         update(up[x].p,1);
     53 }
     54 
     55 void solve(){
     56     l=1,r=0,now=0;
     57     for(int i=1;i<=num1;i++){
     58         if(r<ask[i].R){
     59             for(r=r+1;r<ask[i].R;r++)
     60                 update(r,1);
     61             update(r,1);
     62         }
     63         if(l>ask[i].L){
     64             for(l=l-1;l>ask[i].L;l--)
     65                 update(l,1);
     66             update(l,1);
     67         }
     68         if(r>ask[i].R){
     69             for(;r>ask[i].R;r--)
     70                 update(r,-1);
     71         }
     72         if(l<ask[i].L){
     73             for(;l<ask[i].L;l++)
     74                 update(l,-1);
     75         }
     76         if(now<ask[i].tim){
     77             for(now=now+1;now<ask[i].tim;now++)
     78                 in_time(now);
     79             in_time(now);
     80         }
     81         if(now>ask[i].tim){
     82             for(;now>ask[i].tim;now--)
     83                 out_time(now);
     84         }
     85         ask[i].ans=ans;
     86     }
     87 }
     88 
     89 int main(){
     90     scanf("%d%d",&n,&q);
     91     for(int i=1;i<=n;i++){
     92         scanf("%d",&val[i]);
     93     }
     94     block=sqrt(n);
     95     for(int i=1;i<=n;i++)
     96         belong[i]=(i-1)/block+1;
     97     char c;
     98     int l,r;
     99     for(int i=1;i<=q;i++){
    100         scanf(" %c",&c);
    101         if(c=='Q'){
    102             num1++;
    103             scanf("%d%d",&ask[num1].L,&ask[num1].R);
    104             ask[num1].id=num1;ask[num1].tim=num2;
    105         }else{
    106             num2++;
    107             scanf("%d%d",&up[num2].p,&up[num2].v);
    108             up[num2].z=0;
    109         }
    110     }
    111     sort(ask+1,ask+1+num1);
    112     solve();
    113     sort(ask+1,ask+1+num1,cmp);
    114     for(int i=1;i<=num1;i++)
    115         printf("%d
    ",ask[i].ans);
    116 
    117 return 0;
    118 }
    View Code
  • 相关阅读:
    优秀程序设计的Kiss原则(keep it simple,stupid)
    前端模块化 (好文分享)
    sublime 常用快捷键(转)
    认识与入门 MarkDown (转Te_Lee)
    Sublime Text 3 常用插件以及安装方法(转)
    Flex 布局
    eclipse neon 离线安装插件
    mysql 自动备份命令
    java大并发数据保存方案
    基于webapi的移动互联架构
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9589509.html
Copyright © 2011-2022 走看看