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
心之所动 且就随缘去吧