洛谷 P1903 BZOJ 2120 清橙 A1274【模板】分块/带修改莫队(数颜色)(周奕超)

简介: 试题来源   2011中国国家集训队命题答辩 题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

试题来源

  2011中国国家集训队命题答辩

题目描述

墨墨购买了一套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

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

 

吐槽

  这题A得不容易啊!从前一天晚上开始敲,但是第一次敲,对于原理理解不足,许多细节出了实现偏差差错,交到洛谷上,洛谷自造数据特性太平均全部爆零,洛谷还不提供数据,不得已搬到其他OJ上交,BZOJ不用说了,结果就一个WA,codevs没收这题,COGS(提供许多数据下载)交上去找不到输出文件,最后终于找到了清橙,虽然也不提供数据下载,但清橙的数据分布合理啊——

  不像其他OJ,没有达到我查错的目的。我在清橙上交了一堆60,于是把差错范围锁定到了颜色更换的部分,长乐一中集训DAY3一整天挤出时间,一点点改错(前一天晚上写的简直是混乱不堪啊),终于在去华莱士吃完晚饭回来后AC了这题华莱士吼啊

解题思路

  待修改的莫队只需要在四个更改区间左右端点的四重循环前加上两重更新颜色的循环即可。

  另外极其重要的一点是注意莫队的初始化,初始左右端点之间的颜色要先统计了。一定要注意如果要修改的颜色不在统计范围内,那么改颜色即可,不必改颜色种数(事后说起来好简单啊,调的时候就是改不出来)

源代码

#include<math.h>
#include<cstdio>
#include<cstring>
#include<algorithm>

int n,m;
int color[10010]={0};
int last [10010]={0};
int f[1000010]={0};//离散化后颜色统计
bool vis[10010]={0};
struct query{
    int id,l,pos,r;
    int t;//上一个修改的change_cnt
    int ans;
}an[10010];
int query_cnt=0;
int aa[10010]={0};
int cmp(const query & a,const query& b)
{
    if(a.pos==b.pos)
    {
        if(a.r==b.r)
            return a.t<b.t;
        return a.r<b.r;
    }
    return a.pos<b.pos;
}


void add(int & sum,int pos)
{
    f[color[pos]]++;
    if(f[color[pos]]==1) sum++;
    vis[pos]=1;
}
void del(int & sum,int pos)
{
    f[color[pos]]--;
    if(!f[color[pos]]) sum--;
    vis[pos]=0;
}

struct Change{
    int t,pos,qian,hou;
}ch[10010];
int change_cnt=0;

int main()
{
    //freopen("nt2011_color1.in","r",stdin);//在cogs上提交的记号
    //freopen("nt2011_color1.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&color[i]);
        last[i]=color[i];
    }
    for(int i=1,x,y,kuai=pow(n,2.0/3.0);i<=m;i++)
    {
        char c;
        scanf("\n%c %d %d",&c,&x,&y);
        if(c=='Q')
            query_cnt++,an[query_cnt]={query_cnt,x,x/kuai,y,change_cnt,0};
        else
            change_cnt++,ch[change_cnt]={change_cnt,x,last[x],y},last[x]=y;
    }
    std::sort(an+1,an+query_cnt+1,cmp);
    f[color[1]]++;vis[1]=1;
    for(int i=1,l=1,r=1,sum=1;i<=query_cnt;i++)
    {
        for(int j=an[i-1].t+1;j<=an[i].t;j++)
        {
            if(vis[ch[j].pos])
            {
                del(sum,ch[j].pos);
                color[ch[j].pos]=ch[j].hou;
                add(sum,ch[j].pos);
            }
            else color[ch[j].pos]=ch[j].hou;
        }
        for(int j=an[i-1].t;j>an[i].t;j--)
        {
            if(vis[ch[j].pos])
            {
                del(sum,ch[j].pos);
                color[ch[j].pos]=ch[j].qian;
                add(sum,ch[j].pos);
            }
            else color[ch[j].pos]=ch[j].qian;
        }
        
        while(r<an[i].r) r++,add(sum,r);
        while(l<an[i].l) del(sum,l),l++;
        while(r>an[i].r) del(sum,r),r--;
        while(l>an[i].l) l--,add(sum,l);
        an[i].ans=sum;
    }
    for(int i=1;i<=query_cnt;i++)
        aa[an[i].id]=an[i].ans;
    for(int i=1;i<=query_cnt;i++)
        printf("%d\n",aa[i]);
    return 0;
}

 

目录
相关文章
|
6月前
|
算法 测试技术
枚举(蓝桥练习)(反倍数、特别数的和、找到最多的数、小蓝的漆房、小蓝和小桥的挑战)
枚举(蓝桥练习)(反倍数、特别数的和、找到最多的数、小蓝的漆房、小蓝和小桥的挑战)
|
定位技术
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
177 0
|
5月前
|
C++
【洛谷 P2241】统计方形(数据加强版)题解(循环枚举)
该题目是1997年普及组的一道编程题,要求计算$n\times m$棋盘中的正方形和长方形数量(不计正方形)。输入包含两正整数$n,m\leq 5000$。输出为一行,两个正整数分别表示正方形和长方形数量。示例输入`2 3`,输出`8 10`。解题思路是将矩形数拆分为正方形数和长方形数,然后通过双重循环计算。AC代码使用C++编写,通过累加方法得出结果。
51 0
学C的第二十四天【练习:1. 打印菱形;2. 打印自幂数;3. 求Sn=a+aa..n项之和;4. 喝汽水问题;5. 调整数组使奇数位于偶数前面;6. 打印X形图案;7……;8……;9……;10……】-2
5. 调整数组使奇数全部都位于偶数前面 题目: 输入一个整数数组,实现一个函数, 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分, 所有偶数位于数组的后半部分。
126 0
|
存储 算法
leetcode-每日一题1252. 奇数值单元格的数目(模拟优化)
时间复杂度:O(q * (m + n) + m * n) 其中q表示 indices 数组的长度,m、n为矩阵的行数和列数,遍历 indices 数组都要更新一次行列,总共需要O(q * (m + n))的时间,最后遍历一次矩阵,总共需要O(m * n)的时间
63 0
leetcode-每日一题1252. 奇数值单元格的数目(模拟优化)
|
索引
每日三题-下一个排列、颜色分类、寻找重复数
每日三题-下一个排列、颜色分类、寻找重复数
80 0
每日三题-下一个排列、颜色分类、寻找重复数
|
算法
算法练习题(六)——Z字型打印矩阵
算法练习题(六)——Z字型打印矩阵
115 0