您的位置:首页 > 其它

洛谷 P2056 采花 - 莫队算法

2017-05-12 22:02 295 查看
萧芸斓是 Z国的公主,平时的一大爱好是采花。

今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花。

公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。 由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了 m 个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案! ) ,最后会选择令公主最高兴的行程(为了拿到更多奖金! ) 。

输入输出格式

输入格式

第一行四个空格隔开的整数 n、c 以及 m。

接下来一行 n 个空格隔开的整数,每个数在[1, c]间,第i 个数表示第 i 朵花的颜色。

接下来 m 行每行两个空格隔开的整数 l 和 r(l ≤ r) ,表示女仆安排的行程为公主经过第 l 到第r 朵花进行采花。

输出格式

共m行, 每行一个整数, 第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。

输入输出样例

输入样例#1:

5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5


输出样例#1:

2
0
0
1
0


说明

对于100%的数据,1 ≤ n ≤10^5,c ≤ n,m ≤ 10^5。

(这题Codevs上也有,只不过,数据范围强制用O(nlog2n)的做法)

  分块的数据范围,支持离线,O(1)进行更新,不用莫队还用什么?(我只是建立在降低思考难度和骗分上想的)

Code

/**
* luogu.org
* Problem#2056
* Accepted
* Time:1100ms
* Memory:14179k
*/
#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<ctime>
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<vector>
#ifndef WIN32
#define AUTO "%lld"
#else
#define AUTO "%I64d"
#endif
using namespace std;
typedef bool boolean;
#define inf 0xfffffff
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline boolean readInteger(T& u) {
char x;
int aFlag = 1;
while(!isdigit((x = getchar())) && x != '-' && x != -1);
if(x == -1)    {
ungetc(x, stdin);
return false;
}
if(x == '-') {
aFlag = -1;
x = getchar();
}
for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
u *= aFlag;
ungetc(x, stdin);
return true;
}

typedef class Segment {
public:
int from;
int end;
int first;
int id;
Segment():from(0), end(0), first(0), id(0) {        }

boolean operator < (Segment b) const {
if(first != b.first)    return first < b.first;
return end < b.end;
}
}Segment;

int n, c, q;
int m;
int *flo;
Segment* seg;
int *res;
int *counter;

inline void init() {
readInteger(n);
readInteger(c);
readInteger(q);
flo = new int[(const int)(n + 1)];
seg = new Segment[(const int)(q + 1)];
res = new int[(const int)(q + 1)];
counter = new int[(const int)(c + 1)];
m = (int)sqrt(n + 0.5);
for(int i = 1; i <= n; i++)
readInteger(flo[i]);
for(int i = 1; i <= q; i++) {
readInteger(seg[i].from);
readInteger(seg[i].end);
seg[i].first = seg[i].from / m;
seg[i].id = i;
}
}

inline void solve() {
sort(seg + 1, seg + q + 1);
int val, mdzz = 1;
for(int id = 0; id <= m; id++) {
val = 0;
int l = 1, r = 1;
memset(counter, 0, sizeof(int) * (c + 1));
for(; mdzz <= q && seg[mdzz].first == id; mdzz++) {
while(r <= seg[mdzz].end) {
counter[flo[r]]++;
if(counter[flo[r]] == 2)    val++;
r++;
}
while(l < seg[mdzz].from) {
counter[flo[l]]--;
if(counter[flo[l]] == 1)    val--;
l++;
}
while(l > seg[mdzz].from) {
l--;
counter[flo[l]]++;
if(counter[flo[l]] == 2)    val++;
}
res[seg[mdzz].id] = val;
}
}
for(int i = 1; i <= q; i++)
printf("%d\n", res[i]);
}

int main() {
init();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: