文章总数25祭+莫队略解
莫队,啥东东?
就是“排序巧妙优化复杂度,带来NOIP前的最后一丝宁静。几个活蹦乱跳的指针的跳跃次数,决定着莫队算法的优劣……”
所以,莫队几乎可以解决一切区间问题
比如
这道题
哈哈
其实是一道莫队入门题
我们先来想离线算法
如图:
那么…
我们如何从第一次询问转移到第二次询问呐?
很简单
我们定两个指针:l和r
然后,就有好玩的事发生了!
两个区间的转移:
事实上是L指针往左/右移,R指针往左/右移
转移增么写?
定义一个数组happen[i]
表示当前区间数字i出现的次数
则可以轻易地转移happen了。
但是题目不仅如此,还要我们计算它们的平方和
所以:
当每次移指针时,ans减去happen[last]2 加上happen[now]2 即可
恭喜你已经YY出了原始莫队!
但是复杂度仍是不堪入目
要是跳的太远,会还原成O(nm)级别的(暴力)
所以莫队的精髓来了:排序
怎么排?
要用到分块优化
定义b[i]
表示第i个数所属块
定义u
表示块数
u=sqrt(n)
b[i]=(i/u)+1
然后排序
如果两个区间的l在同块内,r小的排前面。
否则l小的排前面
为什么不以l为第一关键字,r为第二关键字排序内?
我也不知道
举个例子:
1 2
2 100000
3 3
自己体会一下即可
例题:
HH的项链
模板!
但是很遗憾,莫队只有80分
80pts:
#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
struct node{
int l,r;
int Rk;
int ans;
}s[N];
int n,m;
int col[N];
int u;
int b[N];
int happen[5000005]={0};
int ans=0;
int l,r;
bool cmp(node x,node y){
if(b[x.l]==b[y.l]) return x.r<y.r;
return x.l<y.l;
}
bool kmp(node x,node y){
return x.Rk<y.Rk;
}
int main(){
scanf("%d",&n);
u=sqrt(n);
for(register int i=1;i<=n;i++) b[i]=(i/u)+1;//计算所属块
for(register int i=1;i<=n;i++) scanf("%d",&col[i]);
scanf("%d",&m);
for(register int i=1;i<=m;i++){
scanf("%d%d",&s[i].l,&s[i].r);
s[i].Rk=i;
}
sort(s+1,s+m+1,cmp);
for(register int i=1;i<=m;i++){
if(i==1){
for(register int j=s[i].l;j<=s[i].r;j++){
happen[col[j]]++;
if(happen[col[j]]==1) ans++;
}
s[i].ans=ans;
}
else{
while(l<s[i].l){
l++;
happen[col[l-1]]--;
if(happen[col[l-1]]==0) ans--;
}
while(l>s[i].l){
l--;
happen[col[l]]++;
if(happen[col[l]]==1) ans++;
}
while(r<s[i].r){
r++;
happen[col[r]]++;
if(happen[col[r]]==1) ans++;
}
while(r>s[i].r){
r--;
happen[col[r+1]]--;
if(happen[col[r+1]]==0) ans--;
}
s[i].ans=ans;
}
l=s[i].l,r=s[i].r;
}
sort(s+1,s+m+1,kmp);
for(register int i=1;i<=m;i++){
printf("%d\n",s[i].ans);
}
return 0;
}
海星
P4137 Rmq Problem / mex
简单?
但是:
90:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
struct node{
int l,r;
int ans;
int Rk;
}s[N];
int n,m;
int col[N];
int b[N];
int u;
int happen[N]={0};
int l,r;
int ans=0;
bool cmp(node x,node y){
if(b[x.l]==b[y.l]) return x.r<y.r;
return x.l<y.l;
}
bool kmp(node x,node y){
return x.Rk<y.Rk;
}
int main(){
scanf("%d%d",&n,&m);
u=sqrt(n);
for(int i=1;i<=n;i++) b[i]=(i/u)+1;
for(int i=1;i<=n;i++){
scanf("%d",&col[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&s[i].l,&s[i].r);
s[i].Rk=i;
}
sort(s+1,s+m+1,cmp);
for(int i=1;i<=m;i++){
if(i==1){
for(int j=s[i].l;j<=s[i].r;j++){
happen[col[j]]++;
if(happen[col[j]]==1){
while(happen[ans]) ans++;
}
}
l=s[i].l,r=s[i].r;
}
else{
while(l<s[i].l){
l++;
happen[col[l-1]]--;
if(happen[col[l-1]]==0&&col[l-1]<ans) ans=min(ans,col[l-1]);
}
while(l>s[i].l){
l--;
happen[col[l]]++;
int ii=ans;
while(happen[ii]) ii++;
ans=ii;
}
while(r<s[i].r){
r++;
happen[col[r]]++;
int ii=ans;
while(happen[ii]) ii++;
ans=ii;
}
while(r>s[i].r){
r--;
happen[col[r+1]]--;
if(happen[col[r+1]]==0&&col[r+1]<ans) ans=min(ans,col[r+1]);
}
}
s[i].ans=ans;
}
sort(s+1,s+m+1,kmp);
for(int i=1;i<=m;i++){
printf("%d\n",s[i].ans);
}
return 0;
}
100
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
struct node{
int l,r;
int ans;
int Rk;
}s[N];
int n,m;
int col[N];
int b[N];
int u;
int happen[N]={0};
int l,r;
int ans=0;
bool cmp(node x,node y){
if(b[x.l]==b[y.l]) return x.r<y.r;
return x.l<y.l;
}
bool kmp(node x,node y){
return x.Rk<y.Rk;
}
int main(){
scanf("%d%d",&n,&m);
u=sqrt(n);
for(int i=1;i<=n;i++) b[i]=(i/u)+1;
for(int i=1;i<=n;i++){
scanf("%d",&col[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&s[i].l,&s[i].r);
s[i].Rk=i;
}
sort(s+1,s+m+1,cmp);
for(int i=1;i<=m;i++){
if(i==1){
for(int j=s[i].l;j<=s[i].r;j++){
happen[col[j]]++;
if(happen[col[j]]==1){
while(happen[ans]) ans++;
}
}
l=s[i].l,r=s[i].r;
}
else{
while(l<s[i].l){
l++;
happen[col[l-1]]--;
if(happen[col[l-1]]==0&&col[l-1]<ans) ans=min(ans,col[l-1]);
}
while(l>s[i].l){
l--;
happen[col[l]]++;
if(col[l]==ans) while(happen[ans]) ans++;
}
while(r<s[i].r){
r++;
happen[col[r]]++;
if(col[r]==ans) while(happen[ans]) ans++;
}
while(r>s[i].r){
r--;
happen[col[r+1]]--;
if(happen[col[r+1]]==0&&col[r+1]<ans) ans=min(ans,col[r+1]);
}
}
s[i].ans=ans;
}
sort(s+1,s+m+1,kmp);
for(int i=1;i<=m;i++){
printf("%d\n",s[i].ans);
}
return 0;
}
至为什么要加if(col[l]==ans)我至今不明
我太弱了,以至于不会带修莫队
但是: