您的位置:首页 > 其它

【BZOJ 3236】 [Ahoi2013]作业

2015-04-15 10:03 453 查看

3236: [Ahoi2013]作业

Time Limit: 100 Sec Memory Limit: 512 MB

Submit: 819 Solved: 307

[Submit][Status][Discuss]

Description



Input



Output



Sample Input

3 4

1 2 2

1 2 1 3

1 2 1 1

1 3 1 3

2 3 2 3

Sample Output

2 2

1 1

3 2

2 1

HINT

N=100000,M=1000000

Source

By wangyisong1996加强数据

莫队算法+树状数组。

离线来做,将询问按照分好的块来排序。

接下来就是考虑[l,r][l,r]如何转移到[l,r±1][l,r\pm 1]及[l±1,r][l\pm1,r]。

①对于第一问,直接建权值线段树加加减减即可

②第二问有点麻烦,我的做法是:

树状数组维护一个数值在这段区间出现过为11,否则为00的前缀和;

记录下pre[i],ne[i]pre[i],ne[i]表示与ii数值的相同的前一个,后一个在哪;

v[x]v[x]表示xx这种数值是否在树状数组中值是否为11。

当l−1l-1或者r+1r+1即往队列中加入一个数时,直接判断这个数的v[x]v[x]是否为0,如果是就加入。

当l+1l+1或者r−1r-1即从队列中删除一个数时,要判断在之后的删除中是否还会出现同样的数,如果还会出现的话这一次先不管他;否则判断下一次出现是否在所求区间中,如果不在就删除。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define M 100005
using namespace std;
int pos[M],a[M],v[M],pre[M],ne[M],la[M],t[M][2],ans1[M*10],ans2[M*10],n,m;
struct Query
{
int l,r,a,b,id;
}q[M*10];
int lowbit(int x)
{
return x&(-x);
}
bool cmp(Query a,Query b)
{
if (pos[a.l]==pos[b.l]) return a.r<b.r;
return pos[a.l]<pos[b.l];
}
void Update1(int x,int k)
{
for (int i=x;i<=M-5;i+=lowbit(i))
t[i][0]+=k;
}
void Update2(int s,int x,int k,int l,int r)
{
if (k==1)
{
if (v[x]) return;
for (int i=x;i<=M-5;i+=lowbit(i))
t[i][1]++;
v[x]=1;
return;
}
if (!v[x]) return;
if (k==-1&&s<l&&s) return;
if (k==-2&&s>r) return;
if (s>r||s<l)
{
for (int i=x;i<=M-5;i+=lowbit(i))
t[i][1]--;
v[x]=0;
}
}
int Query(int x,int k)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
ans+=t[i][k];
return ans;
}
void read(int &tmp)
{
tmp=0;
char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=tmp*10+ch-'0';
}
int main()
{
read(n),read(m);
int block=sqrt(n);
for (int i=1;i<=n;i++)
{
pos[i]=(i+block-1)/block;
read(a[i]),pre[i]=la[a[i]],la[a[i]]=i;
}
for (int i=1;i<=n;i++)
la[i]=0;
for (int i=n;i;i--)
ne[i]=la[a[i]],la[a[i]]=i;
for (int i=1;i<=m;i++)
read(q[i].l),read(q[i].r),read(q[i].a),read(q[i].b),q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=q[1].l,r=q[1].l;
Update1(a[l],1),Update2(0,a[l],1,0,0);
for (int i=1;i<=m;i++)
{
int nl=q[i].l,nr=q[i].r;
if (nr>r)
{
r++;
for (;r<=nr;r++)
Update1(a[r],1),Update2(0,a[r],1,0,0);
r--;
}
if (nl>l)
{
for (;l<nl;l++)
Update1(a[l],-1),Update2(ne[l],a[l],-1,nl,nr);
}
if (nl<l)
{
l--;
for (;l>=nl;l--)
Update1(a[l],1),Update2(0,a[l],1,nl,nr);
l++;
}
if (nr<r)
{
for (;r>nr;r--)
Update1(a[r],-1),Update2(pre[r],a[r],-2,nl,nr);
}
ans1[q[i].id]=Query(q[i].b,0)-Query(q[i].a-1,0);
ans2[q[i].id]=Query(q[i].b,1)-Query(q[i].a-1,1);
}
for (int i=1;i<=m;i++)
printf("%d %d\n",ans1[i],ans2[i]);
return 0;
}




感悟:

1.莫队好慢啊,树套树会快一点。。

2.这题细节有点多:

①首先要注意主程序中更新l,rl,r的顺序,避免出现l>rl>r的情况

②在处理第二问的Update2中,如果是删除要注意v[x]是否为1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: