Description
萧芸斓是Z国的公主,平时的一大爱好是采花。
今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花。公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了m个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。
Input
第一行四个空格隔开的整数n、c以及m。接下来一行n个空格隔开的整数,每个数在[1, c]间,第i个数表示第i朵花的颜色。接下来m行每行两个空格隔开的整数l和r(l ≤ r),表示女仆安排的行程为公主经过第l到第r朵花进行采花。
Output
共m行,每行一个整数,第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。
Sample Input
5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5Sample Output
2
0 0 1 0
「样例说明」
询问[1, 5]:公主采颜色为1和2的花,由于颜色3的花只有一朵,公主不采;询问[1, 2]:颜色1和颜色2的花均只有一朵,公主不采;
询问[2, 2]:颜色2的花只有一朵,公主不采;
询问[2, 3]:由于颜色2的花有两朵,公主采颜色2的花;
询问[3, 5]:颜色1、2、3的花各一朵,公主不采。HINT
「数据范围」
对于100%的数据,1 ≤ n ≤ 10^6,c ≤ n,m ≤10^6。
这个题和上一个题有点类似(bzoj1878),维护的一个表示区间内至少出现两次的数的种数的树状数组。
pre[i]表示上一个和i位置相同颜色花的位置,我们每次更新不再是update(i,1)
而是update(pre[i],1)即加上 上一个位置的相同颜色花的影响和update(pre[pre[i]],-1)去除上上一次相同颜色花的影响。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#define PI atan(1.0) * 4
#define e 2.718281828
#define rp(i, s, t) for (i = (s); i <= (t); i++)
#define RP(i, s, t) for (i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a, b) memset(a, b, sizeof(a))
#define push_back() pb()
#define fastIn \
ios_base::sync_with_stdio(0); \
cin.tie(0);
using namespace std;
inline int read()
{
int a = 0, b = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
b = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
a = (a << 3) + (a << 1) + c - '0';
c = getchar();
}
return a * b;
}
inline void write(int n)
{
if (n < 0)
{
putchar('-');
n = -n;
}
if (n >= 10)
write(n / 10);
putchar(n % 10 + '0');
}
const int N = 1e6 + 7;
int n;
int a[N], ans[N], last[N], sum[N], pre[N];
struct node
{
int l, r, num;
} p[N];
int lowbit(int x)
{
return x & (-x);
}
void update(int i, int x)
{
while (i <= n)
{
sum[i] += x;
i += lowbit(i);
}
}
int query(int i)
{
int res = 0;
while (i >= 1)
{
res += sum[i];
i -= lowbit(i);
}
return res;
}
bool cmp(node p1, node p2)
{
return p1.r < p2.r;
}
int main()
{
n = read();
int c = read(), m = read();
int i, j;
rp(i, 1, n)
{
a[i] = read();
if (last[a[i]]!=0)
pre[i] = last[a[i]];
last[a[i]] = i;
}
rp(i, 1, m) p[i].l = read(), p[i].r = read(), p[i].num = i;
sort(p + 1, p + 1 + m, cmp);
int nowqueues = 1;
rp(i, 1, n)
{
if (pre[pre[i]]!=0)
update(pre[pre[i]], -1);
if (pre[i]!=0)
update(pre[i], 1);
while (p[nowqueues].r == i)
{
ans[p[nowqueues].num] = query(p[nowqueues].r) - query(p[nowqueues].l - 1);
nowqueues++;
}
}
rp(i, 1, m)
printf("%d\n", ans[i]);
return 0;
}
还有一种做法,可以用莫队来做,也算是经典的做法,很牛皮的暴力,其实就是从小区间推大区间的做法。
具体有关莫队的思想可以参考这篇博文(https://www.cnblogs.com/muzu/articles/7708349.html)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define e 2.718281828
#define rp(i,s,t) for (i = (s); i <= (t); i++)
#define RP(i,s,t) for (i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define push_back() pb()
#define fastIn \
ios_base::sync_with_stdio(0); \
cin.tie(0);
using namespace std;
inline int read()
{
int a=0,b=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
b=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
a=(a<<3)+(a<<1)+c-'0';
c=getchar();
}
return a*b;
}
inline void write(int n)
{
if(n<0)
{
putchar('-');
n=-n;
}
if(n>=10)
write(n/10);
putchar(n%10+'0');
}
const int N=2e5+7;
struct node{
int l,r,m,id;
bool operator< (const node &others) const{
return m==others.m?r<others.r:m<others.m;
}
}p[N];
int a[N],sum[N*20],res[N];
int main(){
int n=read(),i;
rp(i,1,n)
a[i]=read();
int Size=sqrt(n),cnt=0;
int m=read();
rp(i,1,m){
int x=read(),y=read();
p[++cnt].l=x,p[cnt].r=y,p[cnt].id=i,p[cnt].m=(x-1)/Size+1;
}
sort(p+1,p+cnt+1);
int ans=0,l=0,r=0;
rp(i,1,cnt){
while(l<p[i].l) {sum[a[l]]--;if(!sum[a[l]]) ans--;l++;}
while(l>p[i].l) {l--,sum[a[l]]++;if(sum[a[l]]==1) ans++;}
while(r<p[i].r) {r++,sum[a[r]]++;if(sum[a[r]]==1) ans++;}
while(r>p[i].r) {sum[a[r]]--;if(!sum[a[r]]) ans--;r--;}
res[p[i].id]=ans;
}
rp(i,1,cnt) printf("%d\n",res[i]);
return 0;
}