zoukankan      html  css  js  c++  java
  • P1903 [国家集训队]数颜色 (带修改莫队)

    题目描述

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

    1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    2、 R P Col 把第P支画笔替换为颜色Col。

    为了满足墨墨的要求,你知道你需要干什么了吗?

    输入输出格式

    输入格式:

    第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。

    第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。

    第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

    输出格式:

    对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    输入输出样例

    输入样例#1: 复制
    6 5
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6
    输出样例#1: 复制
    4
    4
    3
    4
    

    说明

    对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

    来源:bzoj2120

      1 //感谢xxy dalao的指导, 虽然不得不看了blog才A了这道题。。。。 
      2 
      3 //但是为什么他们一个 dfs 10+ ms就过,我却跑了100+ ?。。。。。 
      4 
      5 #include<iostream>
      6 #include<cstdio>
      7 #include<cstring>
      8 #include<cmath>
      9 #include<algorithm>
     10 using namespace std;
     11 
     12 const int N=1e4+5;
     13 const int M=1e6+5;
     14 
     15 int n,m;
     16 int a[N];
     17 int ans;
     18 int belong[N];
     19 int c[M];
     20 int query_cnt,modify_cnt;
     21 struct Query    //询问操作 
     22 {
     23     int ans;    //这次询问的答案 
     24     int l,r;    //这次询问的左右区间 
     25     int tim;    //这是第几次询问,便于最后将询问排序输出ans 
     26     int tim_modify;        //记录这次询问是在第几次修改之后的,便于修改和撤销 
     27 }query[N];
     28 struct Modify    //修改操作 
     29 {
     30     int tim;    //这是第几次修改操作 
     31     int pos,col,pre_col;    //修改的位置、修改之前的颜色、修改之后的颜色 
     32 }modify[N];
     33 
     34 int read()
     35 {
     36     char c=getchar();int num=0;
     37     for(;!isdigit(c);c=getchar())
     38         if(c=='Q')
     39             return 1;
     40         else if(c=='R')
     41             return 2;
     42     for(;isdigit(c);c=getchar())
     43         num=num*10+c-'0';
     44     return num;
     45 }
     46 
     47 bool cmp1(const Query &a,const Query &b)    //将询问操作排序 
     48 {
     49     if(belong[a.l]==belong[b.l])    //为了保证效率,按照三个关键字排序,前两个和普通的不带修改的莫队一样,第三个关键字是修改时间 
     50         if(belong[a.r]==belong[b.r])
     51             return a.tim_modify<b.tim_modify;
     52         else
     53             return belong[a.r]<belong[b.r];
     54     return belong[a.l]<belong[b.l];
     55 }
     56 
     57 bool cmp2(const Query &a,const Query &b)    //将query按照询问时间排序,便于输出ans 
     58 {
     59     return a.tim<b.tim;
     60 }
     61 
     62 int main()
     63 {
     64     n=read(),m=read();
     65     int size=sqrt(n);
     66     for(int i=1;i<=n;++i)
     67         a[i]=read(),belong[i]=(i-1)/size+1;
     68     for(int i=1,type;i<=m;++i)
     69     {
     70         type=read();
     71         if(type==1)
     72         {
     73             ++query_cnt;
     74             query[query_cnt].l=read();
     75             query[query_cnt].r=read();
     76             query[query_cnt].tim=query_cnt;        //记录这是第几次询问 
     77             query[query_cnt].tim_modify=modify_cnt;        //记录当前询问是在第几次修改之后 
     78         }
     79         else
     80         {
     81             ++modify_cnt;
     82             modify[modify_cnt].pos=read();
     83             modify[modify_cnt].col=read();    //修改之后的值 
     84             modify[modify_cnt].tim=modify_cnt;
     85             modify[modify_cnt].pre_col=a[modify[modify_cnt].pos];    //记录修改之前的值 
     86             a[modify[modify_cnt].pos]=modify[modify_cnt].col;    //修改 
     87         }
     88     }
     89     for(int i=modify_cnt;i;--i)        //把修改了的a数组还原回去 
     90         a[modify[i].pos]=modify[i].pre_col;
     91     sort(query+1,query+query_cnt+1,cmp1);
     92     int now_modify=0,l=1,r=0;
     93     for(int i=1;i<=query_cnt;++i)        //当时被卡在了修改和撤销上,没理解透彻,不知道该不该更新ans,因为当时觉得如果更新了ans的话会让后边在移动左右端点更新值得时候重复,其实不然,因为如果当前修改的值在当前询问的区间中,那么它是不会被更改的(因为改到左右端点的时候就停止了,不会来改它),如果不在当前询问的区间内,那么在移动端点的时候,被+1的ans会被还原回去(-1),但是被-1的ans是不会变的,因为它已经没了(滑稽) 
     94     {
     95         if(query[i].tim_modify>now_modify)    //当前询问在上次修改操作之后,往后修改 
     96         {
     97             for(int j=now_modify+1;j<=query[i].tim_modify;++j)
     98             {
     99                 if(modify[j].pos>=l&&modify[j].pos<=r)        //如果修改的位置在上次询问的区间内,更新 
    100                 {
    101                     --c[modify[j].pre_col];
    102                     if(!c[modify[j].pre_col])
    103                         --ans;
    104                     if(!c[modify[j].col]) 
    105                         ++ans;
    106                     ++c[modify[j].col];
    107                 }
    108                 a[modify[j].pos]=modify[j].col;        //修改 
    109             }
    110         }
    111         if(query[i].tim_modify<now_modify)        //当前询问在上次修改操作之前,撤销修改 
    112         {
    113             for(int j=now_modify;j>query[i].tim_modify;--j)
    114             {
    115                 if(modify[j].pos>=l&&modify[j].pos<=r)
    116                 {
    117                     --c[modify[j].col];        //把修改后的数的值还原回去 
    118                     if(!c[modify[j].col])
    119                         --ans;
    120                     if(!c[modify[j].pre_col])    //被修改了的数的值还原回去 
    121                         ++ans;
    122                     ++c[modify[j].pre_col];
    123                 }
    124                 a[modify[j].pos]=modify[j].pre_col;        //撤销 
    125             }
    126         }
    127         if(l<query[i].l)
    128         {
    129             for(int j=l;j<query[i].l;++j)
    130             {
    131                 --c[a[j]];
    132                 if(!c[a[j]])
    133                     --ans;
    134             }
    135         }
    136         if(l>query[i].l)
    137         {
    138             for(int j=query[i].l;j<l;++j)
    139             {
    140                 if(!c[a[j]])
    141                     ++ans;
    142                 ++c[a[j]];
    143             }
    144         }
    145         if(r<query[i].r)
    146         {
    147             for(int j=r+1;j<=query[i].r;++j)
    148             {
    149                 if(!c[a[j]])
    150                     ++ans;
    151                 ++c[a[j]];
    152             }
    153         }
    154         if(r>query[i].r)
    155         {
    156             for(int j=query[i].r+1;j<=r;++j)
    157             {
    158                 --c[a[j]];
    159                 if(!c[a[j]])
    160                     --ans;
    161             }
    162         }
    163         l=query[i].l,r=query[i].r;    //更新查询区间 
    164         query[i].ans=ans;    //记录这次查询的答案 
    165         now_modify=query[i].tim_modify;        //更新最新一次修改时间 
    166     }
    167     sort(query+1,query+query_cnt+1,cmp2);
    168     for(int i=1;i<=query_cnt;++i)
    169     {
    170         printf("%d
    ",query[i].ans);
    171     }
    172     return 0;
    173 }
  • 相关阅读:
    python百度ai的银行卡识别代码
    python百度ai的身份证识别代码
    Linux下安装jupyter
    HADOOP 与 jupyterlab 链接
    csv文件数据导出到mongo数据库
    Contos7 常用命令
    centos 安装Python3 及对应的pip
    PHP 连接数据库
    java 注解学习记录
    java简单实现搜索指定后缀文件
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8439736.html
Copyright © 2011-2022 走看看