分块 公主的朋友
问题 B: 公主的朋友
时间限制: 1 Sec 内存限制: 256 MB题目描述
由于 Wulala 在上个问题中的精彩表现,公主认为 Wulala 是一个很棒的人,就把 Wulala 留在了 X 国。这时正好公主的一位传教士朋友来拜访公主,于是想找 wulala 帮忙X 国如同一条直线,其中有 n 个城市,从东向西分别编号为 1~n。而他的国家中有 m 种宗教,每个城市一定会有一种信仰的宗教。
有时候有些城市为了获得更多的认可,会派出信仰本城市宗教的传教士前往其他国家。X 国
的传教士都十分厉害,只要是他途经的地方都会改信他所传播的宗教。
传教士们在路上碰到自己宗教的城市自然就不用传教了,可以停下来看看里番啥的,所以每
一个传教士在旅行前都会计算自己可以在多少城市停下来(不包括起始的城市)。
而传教士们都是文科僧,数学是很差的,所以他希望 Wulala 能帮他计算。可 Wulala 数学也不好,但他又不想在公主面前丢脸,你能帮帮他吗?
输入
第一行两个整数 n,m
第二行 n 个整数第 i 个整数代表第 i 各城市信仰的宗教
第三行一个整数 T 代表传教士的个数
接下来 T 行每行两个整数 x,y 代表 x 城向 y 城派遣了一个传教士(保证 x < y)
输出
输出 T 行,第 i 行代表第 i 个传教士询问的答案
样例输入
2 21 221 21 2
样例输出
01
提示
对于 30%的数据 n <= 100000, m <= 10, T <= 100
对于 60%的数据 n <= 100000, m <= 10, T <= 100000
对于 100%的数据 n <= 100000, m <= 300, T <= 100000
可以用线段树,但分块很好想啊。。联考时又AC了一道。。
比普通分块,我脑补出了一种分块延迟标记。指这个块如果被某个zz传教士横跨了过去,就是说这个块全变成了某一个宗教,打上个标记,记录这个块变成了某个宗教。如果这个块又被整个遍历,就不用把延迟下传。而如果这个块被当做散点遍历了,就要把标记下传,更新。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #define N 100000 using namespace std; int read() { int sum=0,f=1;char x=getchar(); while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();} while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();} return sum*f; } int n,m,a[N+5],kuai[N+5],h,t,v[N+5],s[2000][305]; int get(int l,int r) { if(v[kuai[l-1]])a[l-1]=v[kuai[l-1]]; int f=a[l-1],sum=0; if(kuai[l]==kuai[r]) { if(v[kuai[l]]==f) return r-l+1; else { if(v[kuai[l]]!=0) for(int i=(kuai[l]-1)*h+1;i<=min(n,kuai[l]*h);i++)a[i]=v[kuai[l]]; v[kuai[l]]=0; for(int i=l;i<=r;i++) if(a[i]!=f) { s[kuai[l]][a[i]]--; s[kuai[l]][f]++; a[i]=f; } else sum++; return sum; } } else { if(v[kuai[l]]==f) sum+=kuai[l]*h-l+1; else { if(v[kuai[l]]!=0) for(int i=(kuai[l]-1)*h+1;i<=kuai[l]*h;i++)a[i]=v[kuai[l]]; v[kuai[l]]=0; for(int i=l;i<=kuai[l]*h;i++) if(a[i]!=f) { s[kuai[l]][a[i]]--; s[kuai[l]][f]++; a[i]=f; } else sum++; } if(v[kuai[r]]==f) sum+=r-(kuai[r]-1)*h; else { if(v[kuai[r]]!=0) for(int i=(kuai[r]-1)*h+1;i<=min(n,kuai[r]*h);i++)a[i]=v[kuai[r]]; v[kuai[r]]=0; for(int i=(kuai[r]-1)*h+1;i<=r;i++) if(a[i]!=f) { s[kuai[r]][a[i]]--; s[kuai[r]][f]++; a[i]=f; } else sum++; } for(int i=kuai[l]+1;i<kuai[r];i++) if(v[i]==f) sum+=h; else { sum+=s[i][f]; v[i]=f; for(int j=1;j<=m;j++)s[i][j]=0; s[i][f]=h; } return sum; } return sum; } int main() { n=read();m=read();h=sqrt(n);if(h>70)h=70; for(int i=1;i<=n;i++) { a[i]=read(); kuai[i]=(i-1)/h+1; s[kuai[i]][a[i]]++; } t=read(); int l,r,sum=0; for(int i=1;i<=t;i++) { l=read(); r=read(); if(l==r){printf("0\n");continue;} sum=get(l+1,r); printf("%d\n",sum); }