您的位置:首页 > 其它

[BZOJ3809]Gty的二逼妹子序列(莫队+分块)

2018-01-24 19:36 267 查看

题目:

我是超链接

题解:

Emmm。我们可以用莫队+树状数组的方法,一般莫队算法题会对位置进行分块,离线询问,以区间左端点所属的块为第一关键字,区间右端点为第二关键字进行排序,然后用树状数组维护一些值之类的。效率是O(mn√logn),根本过不去啊

但是可以采用莫队+权值分块的做法,莫队统计[l,r]内出现的所有数字,对于块外看看这个权值有没有,块内看看第一次出现的权值有多少,直接累加

这里应用的是分块对于一段区间内值的求和

代码:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=100005;
const int M=1000005;
int s
,pos
,cnt,n,m,num
,first
,ans[M];
struct hh{int l,r,a,b,num;}q[M];
int cmp(hh a,hh b)
{
if (pos[a.l]==pos[b.l]) return a.r<b.r;
return pos[a.l]<pos[b.l];
}
int qurry(int l,int r)
{
int ans=0;
if (pos[l]==pos[r])
{
for (int i=l;i<=r;i++)
if (num[i]) ans++;
}else
{
int up=min(n,pos[l]*cnt);
for (int i=l;i<=up;i++)
if (num[i]) ans++;
up=(pos[r]-1)*cnt+1;
for (int i=up;i<=r;i++)
if (num[i]) ans++;
for (int i=pos[l]+1;i<pos[r];i++) ans+=first[i];
}
return ans;
}
int read()
{
char ch=getchar();int x=0,f=1;
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch<='9' && ch>='0') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int main()
{
int Q; n=read(); Q=read();
cnt=sqrt(n);
if (n%cnt) m=n/cnt+1;else m=n/cnt;
for (int i=1;i<=n;i++) pos[i]=(i-1)/cnt+1;
for (int i=1;i<=n;i++) s[i]=read();
for (int i=1;i<=Q;i++)
q[i].l=read(),q[i].r=read(),q[i].a=read(),q[i].b=read(),q[i].num=i;
sort(q+1,q+Q+1,cmp);
int l=1,r=0;
for (int i=1;i<=Q;i++)
{
while (r<q[i].r)
{
r++;num[s[r]]++;
if (num[s[r]]==1) first[pos[s[r]]]++;
}
while (r>q[i].r)
{
num[s[r]]--;
if (!num[s[r]]) first[pos[s[r]]]--;
r--;
}
while (l<q[i].l)
{
num[s[l]]--;
if (!num[s[l]]) first[pos[s[l]]]--;
l++;
}
while (l>q[i].l)
{
l--;num[s[l]]++;
if (num[s[l]]==1) first[pos[s[l]]]++;
}
ans[q[i].num]=qurry(q[i].a,q[i].b);
}
for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: