【分块】bzoj2120 数颜色

分块,在每个点记录一下它之前离它最近的相同颜色的位置pre[i],显然问题转化成了求[l,r]中pre[i]<l的值的个数。

这是分块擅长的,在每个块内记录有序表,查询时对零散的暴力,整块的二分即可。

修改时有点麻烦,设修改a[p]。

可能会对pre[p]产生影响;

可能会对p位置之后的第一个 与a[p]修改前相等的值 的pre 产生影响;

可能会对p位置之后的第一个 与a[p]修改后相等的值 的pre 产生影响。

细节蛮多,调了很久。<---蒟蒻。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,m,sz,sum,l[30],r[30],num[10001],pre[10001],preb[10001],a[10001],x,y,pos[1000001];
 7 int Res,Num;char C,CH[12];
 8 inline int G()
 9 {
10     Res=0;C=‘*‘;
11     while(C<‘0‘||C>‘9‘)C=getchar();
12     while(C>=‘0‘&&C<=‘9‘){Res=Res*10+(C-‘0‘);C=getchar();}
13     return Res;
14 }
15 inline void P(int x)
16 {
17     Num=0;if(!x){putchar(‘0‘);puts("");return;}
18     while(x>0)CH[++Num]=x%10,x/=10;
19     while(Num)putchar(CH[Num--]+48);
20     puts("");
21 }
22 void makeblock()
23 {
24     sz=sqrt((double)n*log2(n)); if(!sz) sz=1;
25     for(sum=1;sum*sz<n;sum++)
26       {
27         l[sum]=(sum-1)*sz+1;
28         r[sum]=sum*sz;
29           for(int i=l[sum];i<=r[sum];i++)
30           num[i]=sum;
31       }
32     l[sum]=sz*(sum-1)+1;
33     r[sum]=n;
34     for(int i=l[sum];i<=r[sum];i++)
35       num[i]=sum;
36 }
37 void makepre()
38 {
39     for(int i=1;i<=n;i++) {pre[i]=pos[a[i]]; pos[a[i]]=i;}
40     memcpy(preb,pre,sizeof(pre));
41     for(int i=1;i<=sum;i++) sort(pre+l[i],pre+r[i]+1);
42 }
43 inline void query()
44 {
45     int res=0;
46     if(num[x]+1>=num[y]) {for(int i=x;i<=y;i++) if(preb[i]<x) res++;}
47     else
48       {
49           for(int i=x;i<=r[num[x]];i++) if(preb[i]<x) res++;
50           for(int i=l[num[y]];i<=y;i++) if(preb[i]<x) res++;
51           for(int i=num[x]+1;i<num[y];i++) res+=lower_bound(pre+l[i],pre+r[i]+1,x)-(pre+l[i]);
52       }
53     P(res);
54 }
55 inline void update()
56 {
57     int t=0;
58     for(int i=x+1;i<=n;i++)
59       if(a[i]==y)
60         {*lower_bound(pre+l[num[i]],pre+r[num[i]],preb[i])=x; preb[i]=x;
61         sort(pre+l[num[i]],pre+r[num[i]]+1); break;}
62     a[0]=y;
63     for(int i=x-1;i>=0;i--)
64       if(a[i]==y)
65         {*lower_bound(pre+l[num[x]],pre+r[num[x]],preb[x])=i; preb[x]=i;
66         sort(pre+l[num[x]],pre+r[num[x]]+1); break;}
67     int t2=a[x]; a[x]=y;
68     for(int i=x;i>=1;i--)
69       if(a[i]==t2)
70         {t=i; break;}
71     for(int i=x+1;i<=n;i++)
72       if(a[i]==t2)
73         {*lower_bound(pre+l[num[i]],pre+r[num[i]],preb[i])=t; preb[i]=t;
74         sort(pre+l[num[i]],pre+r[num[i]]+1); break;}
75 }char op[1];
76 int main()
77 {
78     n=G();m=G();
79     for(int i=1;i<=n;i++) a[i]=G();
80     makeblock(); makepre();
81     for(int i=1;i<=m;i++)
82       {
83         scanf("%s",op);x=G();y=G();
84           if(op[0]==‘Q‘) query();
85           else update();
86       }
87     return 0;
88 }
时间: 2024-10-21 10:36:43

【分块】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

BZOJ2120 数颜色 分块+二分法

题意:给定一个颜色序列,维护:1.单点修改  2.区间查询不同颜色的种数 题解: 定义f[i]为i左边第一个和i颜色相同的位置,用分块来维护f. 询问:看区间中有多少个位置的f[i]<l 更新:暴力枚举p左右最近的与p颜色相同的位置,更新即可 #include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #includ

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

【带修莫队】bzoj2120 数颜色

块大小为n1/3. 把询问和修改分开. 每次两个询问之间的修改进行暴力转移,如果修改在上一次询问的区间里,就会对当前状态形成影响. 好慢. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define N 10001 int num[N],n,m,b[N],a[N],enq,enc,anss[N]; struct ASK{