【BZOJ 3236】 [Ahoi2013]作业
2015-04-15 10:03
453 查看
3236: [Ahoi2013]作业
Time Limit: 100 Sec Memory Limit: 512 MBSubmit: 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
相关文章推荐
- 【树套树】【bzoj 3236】: [Ahoi2013]作业
- 【莫队算法】【权值分块】bzoj3236 [Ahoi2013]作业
- 【bzoj3236】[Ahoi2013]作业【树套树 线段树套主席树】
- BZOJ3236 [Ahoi2013]作业
- [bzoj3236][Ahoi2013]作业(莫队+树状数组)
- BZOJ 3236: [Ahoi2013]作业( 莫队 + BIT )
- 【AHOI 2013】【BZOJ 3236】作业
- bzoj 3236: [Ahoi2013]作业
- BZOJ 3236: [Ahoi2013]作业|莫队算法|树状数组
- [BZOJ 3236] [Ahoi2013] 作业 && [BZOJ 3809] 【莫队(+分块)】
- BZOJ 3809: Gty的二逼妹子序列 & 3236: [Ahoi2013]作业 [莫队]
- BZOJ 3236: [Ahoi2013]作业
- bzoj 3236: [Ahoi2013]作业
- [bzoj 3236--AHOI2013]作业
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
- [BZOJ3236][Ahoi2013]作业(莫队+树状数组)
- 【BZOJ3809/3236】Gty的二逼妹子序列 [Ahoi2013]作业 莫队算法+分块
- bzoj 3236: [Ahoi2013]作业 莫队算法+分块
- 【BZOJ3236】【AHOI2013】作业 线段树 分治 树状数组
- BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块