• [SDOI2008]郁闷的小J(分块)


    [SDOI2008]郁闷的小J

    题目描述

    小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架。虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他面临着被解雇的危险,这也正是他所郁闷的。

    具体说来,书架由N个书位组成,编号从1到N。每个书位放着一本书,每本书有一个特定的编码。

    小J的工作有两类:

    1.图书馆经常购置新书,而书架任意时刻都是满的,所以只得将某位置的书拿掉并换成新购的书。

    2.小J需要回答顾客的查询,顾客会询问某一段连续的书位中某一特定编码的书有多少本。

    例如,共5个书位,开始时书位上的书编码为1,2,3,4,5

    一位顾客询问书位1到书位3中编码为“2”的书共多少本,得到的回答为:1

    一位顾客询问书位1到书位3中编码为“1”的书共多少本,得到的回答为:1

    此时,图书馆购进一本编码为“1”的书,并将它放到2号书位。

    一位顾客询问书位1到书位3中编码为“2”的书共多少本,得到的回答为:0

    一位顾客询问书位1到书位3中编码为“1”的书共多少本,得到的回答为:2

    ……

    你的任务是写一个程序来回答每个顾客的询问。

    输入输出格式

    输入格式:

    第一行两个整数N,M,表示一共N个书位,M个操作。

    接下来一行共N个整数数A1,A2…AN,Ai表示开始时位置i上的书的编码。

    接下来M行,每行表示一次操作,每行开头一个字符

    若字符为‘C’,表示图书馆购进新书,后接两个整数A(1<=A<=N),P,表示这本书被放在位置A上,以及这本书的编码为P。

    若字符为‘Q’,表示一个顾客的查询,后接三个整数A,B,K(1<=A<=B<=N),表示查询从第A书位到第B书位(包含A和B)中编码为K的书共多少本。

    输出格式:

    对每一个顾客的查询,输出一个整数,表示顾客所要查询的结果。

    输入输出样例

    输入样例#1: 复制

    5 5
    1 2 3 4 5
    Q 1 3 2
    Q 1 3 1
    C 2 1
    Q 1 3 2
    Q 1 3 1

    输出样例#1: 复制

    1
    1
    0
    2

    说明

    对于40%的数据,1<=N,M<=5000

    对于100%的数据,1<=N,M<=100000

    对于100%的数据,所有出现的书的编码为不大于2147483647的正数。

    题解

    一眼看上去。
    分块啊!
    点开标签,平衡树???
    平衡树打得少告辞。
    还是用分块水一下吧。
    这个题目类似于教主的魔法。
    我们只需要把每一个块排一遍序。
    然后编号嘛。就是二分一下就好了。
    每次查询一下(O(logn sqrt n))再乘上个(m)就可以了。
    要吸氧,可能是我分块打得太垃圾了吧。
    不吸只有四十分。

    代码

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=1000001;
    int bl[N],l[N],r[N];
    int a[N],ch[N];
    int n,m,k,tmp;
    int read(){
    	int x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    
    void build(){
    	for(int i=1;i<=tmp;i++)
    	l[i]=(i-1)*tmp+1,r[i]=i*tmp;
    	for(int i=1;i<=n;i++)bl[i]=(i-1)/tmp+1;
    	if(r[tmp]<n){
    		tmp++,r[tmp]=n,l[tmp]=r[tmp-1]+1;
    		for(int i=l[tmp];i<=n;i++)bl[i]=tmp;
    	}
    	for(int i=1;i<=tmp;i++){
    		sort(a+l[i],a+r[i]+1);
    	}
    }
    
    void change(int x,int y){
    	ch[x]=y;
    	for(int i=l[bl[x]];i<=r[bl[x]];i++)a[i]=ch[i];
    	sort(a+l[bl[x]],a+r[bl[x]]+1);
    }
    
    int query(int ll,int rr,int v){
    	int ans=0;
    	if(bl[ll]==bl[rr]){
    		for(int i=ll;i<=rr;i++)if(ch[i]==v)ans++;
    		return ans;
    	}
    	for(int i=bl[ll]+1;i<=bl[rr]-1;i++){
    		int lv=lower_bound(a+l[i],a+r[i]+1,v)-a;
    		int rv=lower_bound(a+l[i],a+r[i]+1,v+1)-a-1;
    		ans+=rv-lv+1;
    	}
    	for(int i=ll;i<=r[bl[ll]];i++)
    	if(ch[i]==v)ans++;
    	for(int i=l[bl[rr]];i<=rr;i++)
    	if(ch[i]==v)ans++;
    	return ans;
    }
    
    int main(){
    	n=read();m=read();tmp=sqrt(n);
    	for(int i=1;i<=n;i++){
    		a[i]=ch[i]=read();
    	}
    	build();
    	while(m--){
    		char opt;
    		scanf("%s",&opt);
    		if(opt=='C'){
    			int x=read(),y=read();
    			change(x,y);
    		}
    		if(opt=='Q'){
    			int ll=read(),rr=read(),v=read();
    			printf("%d
    ",query(ll,rr,v));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    java学习笔记(5)
    java学习笔记(4)
    java学习笔记(3)
    java学习笔记(2)
    java学习笔记(1)
    很棒的Nandflash资料
    Tx2440_Lcd
    git-github学习心得
    多文档编辑器
    假设检验
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9593076.html
Copyright © 2020-2023  润新知