您的位置:首页 > 其它

bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)

2016-04-01 16:30 351 查看
【题意】

回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]。

【思路】

考虑使用块状链表实现莫队算法中的插入与删除。

因为权值处于1..n之间,所以我们可以建一个基于权值的块状链表,每个块维护一个区间信息sum,表示权值在该块的数的种数。

这样插入与删除只需要O(1)的时间,查询需要O(sqrt(n))的时间,总的时间复杂度为O(n^1.5+qn^0.5)

【代码】

#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long ll;
const int N = 3e5+10;

ll read() {
char c=getchar();
ll f=1,x=0;
while(!isdigit(c)) {
if(c=='-') f=-1; c=getchar();
}
while(isdigit(c))
x=x*10+c-'0',c=getchar();
return x*f;
}

int n,m,B;
int pos
,sum
,cnt
,a
,ans
;

struct Node
{
int id,l,r,a,b;
bool operator < (const Node& rhs) const
{
return pos[l]<pos[rhs.l]||(pos[l]==pos[rhs.l]&&r<rhs.r);
}
} q
;

void upd(int x,int v)
{
cnt[x]+=v;
if(v==1&&cnt[x]==1) sum[pos[x]]++;
if(v==-1&&cnt[x]==0) sum[pos[x]]--;
}
int query(int l,int r)
{
int bl=pos[l],br=pos[r];
int ans=0;
if(bl==br)
{
FOR(i,l,r) ans+=cnt[i]>0;
return ans;
}
FOR(i,bl+1,br-1) ans+=sum[i];
bl=B*bl;
br=B*(br-1)+1;
FOR(i,l,bl) ans+=cnt[i]>0;
FOR(i,br,r) ans+=cnt[i]>0;
return ans;
}

int main()
{
n=read(),m=read();
FOR(i,1,n) a[i]=read();
B=sqrt(n+0.5);
FOR(i,1,n) pos[i]=(i-1)/B+1;
FOR(i,1,m)
{
q[i].l=read(),q[i].r=read();
q[i].a=read(),q[i].b=read();
q[i].id=i;
}
sort(q+1,q+m+1);
int l=1,r=0;
FOR(i,1,m)
{
while(l<q[i].l) upd(a[l++],-1);
while(l>q[i].l) upd(a[--l],1);
while(r<q[i].r) upd(a[++r],1);
while(r>q[i].r) upd(a[r--],-1);
ans[q[i].id]=query(q[i].a,q[i].b);
}
FOR(i,1,m)
printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: