BZOJ2120 数颜色 分块+二分法

题意:给定一个颜色序列,维护:1、单点修改  2、区间查询不同颜色的种数

题解:

定义f[i]为i左边第一个和i颜色相同的位置,用分块来维护f。

询问:看区间中有多少个位置的f[i]<l

更新:暴力枚举p左右最近的与p颜色相同的位置,更新即可

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXS=100+2;
const int MAXC=1000000+2;
struct BLOCK{
    int a[MAXS],b[MAXS],c[MAXS];
}block[MAXS];
int N,M,S,C,f[MAXC];
char s[3];

void Change(int x,int c){
    int p=(x-1)/S+1,m=(1+S)>>1;
    for(int l=1,r=S;l<r;m=(l+r)>>1){
        if(block[p].b[m]<block[p].a[x-(p-1)*S]) l=m+1;
        else r=m;
    }

    block[p].b[m]=c;
    while(m!=1 && block[p].b[m-1]>block[p].b[m]) swap(block[p].b[m-1],block[p].b[m]),m--;
    while(m!=S && block[p].b[m+1]<block[p].b[m]) swap(block[p].b[m+1],block[p].b[m]),m++;

    block[p].a[x-(p-1)*S]=c;
}

void Update(int x,int c){
    int p=(x-1)/S+1,t=-1;

    for(int i=x+1;i<=N;i++){
        if(block[(i-1)/S+1].c[i-(i-1)/S*S]==block[p].c[x-(p-1)*S]){
            Change(i,block[p].a[x-(p-1)*S]);
            break;
        }
    }

    for(int i=x+1;i<=N;i++)
        if(block[(i-1)/S+1].c[i-(i-1)/S*S]==c){
            Change(i,x);
            break;
        }

    Change(x,-1);
    for(int i=x-1;i;i--)
        if(block[(i-1)/S+1].c[i-(i-1)/S*S]==c){
            Change(x,i);
            break;
        }

    block[p].c[x-S*(p-1)]=c;
}

int Find(int p,int t){
    int m=(1+S)>>1,l=1,r=S;
    while(l<r){
        if(block[p].b[m]>=t) r=m-1;
        else l=m+1;
        m=(l+r)>>1;
    }
    if(block[p].b[l]>=t) l--;
    return l;
}

int Query(int l,int r){
    int ret=0,m=(1+S)>>1,t=l;
    if((l-1)%S){
        int p=(l-1)/S+1;
        for(int i=l-S*(p-1);i<=S && i<=r-S*(p-1);i++)
            if(block[p].a[i]<t) ret++;
        l=S*p+1;
    }

    while(l+S-1<=r) ret+=Find((l-1)/S+1,t),l+=S;

    if(r%S){
        int p=l/S+1;
        for(int i=1;i<=r-S*(p-1);i++)
            if(block[p].a[i]<t) ret++;
    }

    return ret;
}

int main(){
    memset(f,-1,sizeof(f));
    memset(block,0X7F,sizeof(block));

    scanf("%d %d",&N,&M),S=ceil(sqrt((double)N));
    for(int i=1,j=1,k=1,c;i<=N;i++,j++){
        scanf("%d",&block[k].c[j]);
        block[k].a[j]=block[k].b[j]=f[block[k].c[j]],f[block[k].c[j]]=i;
        if(j==S || i==N){
            sort(block[k].b+1,block[k].b+j+1);
            j=0,k++;
        }
    }
    C=(N%S?N/S+1:N/S);

    for(int i=1,a,b;i<=M;i++){
        scanf("%s %d %d",s,&a,&b);
        if(s[0]==‘R‘) Update(a,b);
        if(s[0]==‘Q‘) printf("%d\n",Query(a,b));
    }

    return 0;
}

时间: 2024-10-12 13:06:22

BZOJ2120 数颜色 分块+二分法的相关文章

[Bzoj2120]数颜色 (非正解 )(莫队)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 6286  Solved: 2489[Submit][Status][Discuss] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干

bzoj2120 数颜色 莫队 带修改

[bzoj2120]数颜色 Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? Input 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数.第2行N个整数,分别代表初始画笔排中第i支画笔的颜色.第3行到第2+M行,每行分

BZOJ2120数颜色(带修改莫队)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 7384  Solved: 2998[Submit][Status][Discuss] Description 墨 墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要

BZOJ2120: 数颜色

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 1394  Solved: 516[Submit][Status] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? Inpu

【bzoj2453】维护队列/【bzoj2120】数颜色 分块+二分

题目描述 你小时候玩过弹珠吗? 小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N.为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少.当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色.但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助. 输入 输入文件第一行包含两个整数N和M. 第二行N个整数,表示初始队列中弹珠的颜色. 接下来M行,每行的形式为"Q L R"或"R x c","Q L R&quo

【分块】bzoj2120 数颜色

分块,在每个点记录一下它之前离它最近的相同颜色的位置pre[i],显然问题转化成了求[l,r]中pre[i]<l的值的个数. 这是分块擅长的,在每个块内记录有序表,查询时对零散的暴力,整块的二分即可. 修改时有点麻烦,设修改a[p]. 可能会对pre[p]产生影响: 可能会对p位置之后的第一个 与a[p]修改前相等的值 的pre 产生影响: 可能会对p位置之后的第一个 与a[p]修改后相等的值 的pre 产生影响. 细节蛮多,调了很久.<---蒟蒻. 1 #include<cstdio&

bzoj2120: 数颜色 [莫队][分块]

Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要干什么了吗? Input 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数.第2行N个整数,分别代表初始画笔排中第i支画笔的颜色.第3行到第2+M行,每行分别代表墨墨会做的一件事情,格

bzoj2120: 数颜色 &amp;&amp;bzoj2453: 维护队列

题目大意: 你小时候玩过弹珠吗? 小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N.为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少.当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色.             但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助. 题解:莫队或者分块 代码: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio>

BZOJ2453维护队列&amp;&amp;BZOJ2120数颜色

2016-05-28 11:20:22 共同的思路:维护某种颜色上一次在哪里出现 BZOJ2453 http://www.lydsy.com/JudgeOnline/problem.php?id=2453 BZOJ2120 http://www.lydsy.com/JudgeOnline/problem.php?id=2120 #include<bits/stdc++.h> #define inf 1000000000 #define ll long long #define N 10005