bzoj 1878 [SDOI2009]HH的项链 莫队

数据不是很大,我们可以通过莫队算法来很轻易的解决这个问题。注意不要搞混n,m变量。

按照一定顺序来进行操作询问,使得重复操作尽可能的少。我们考虑从一个已经得出的[l,r]的答案,转移到[a,b]的答案就是两个点的曼哈顿距离。可以使用最小曼哈顿距离生成树来解决。但是代码量过大。我们有更简单的解决策略。分块。我们分成根号n块。

我们考虑如果从一个区间转移到另外一个区间,他们在同一个分块里。那么单次复杂度最多为sqrt(n)。

如果不在同一个分块里。r在不同分块的区间中单调递增。那么最多总共也是m*sqrt(n)。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 #define maxn 1000005
 7 int read()
 8 {
 9     int x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
12     return x*f;
13 }
14 struct node
15 {
16     int l,r,id,where;
17 } q[maxn];
18 int co[maxn];
19 int n,m,sum,am[maxn],num[maxn];
20 bool cmp1(node a,node b)
21 {
22     if(a.where!=b.where)
23         return a.where<b.where;
24     return a.r < b.r;
25 }
26 void add(int now)
27 {
28     if(!am[co[now]]) sum++;
29     am[co[now]]++;
30 }
31 void down(int now)
32 {
33     am[co[now]]--;
34     if(!am[co[now]]) sum--;
35 }
36 int main()
37 {
38     scanf("%d",&n);
39     for(int i=1; i<=n; i++)
40         co[i] = read();
41     scanf("%d",&m);
42     int L=1,R=0;
43     int sz=(int)sqrt(n);
44     for(int i=1; i<=m; i++)
45     {
46         q[i].l = read();
47         q[i].r = read();
48         q[i].where=q[i].l/sz+1;
49         q[i].id=i;
50     }
51     sort(q+1,q+m+1,cmp1);
52     for(int i=1; i<=m; i++)
53     {
54         while(q[i].r>R) add(R+1),R++;
55         while(q[i].l<L) add(L-1),L--;
56         while(q[i].r<R) down(R),R--;
57         while(q[i].l>L) down(L),L++;
58         num[q[i].id]=sum;
59     }
60     for(int i=1; i<=m; i++)
61         printf("%d\n",num[i]);
62     return 0;
63 }
64 
posted @ 2020-01-20 08:34  IAT14  阅读(162)  评论(0编辑  收藏  举报