洛谷 1503

来源:互联网 发布:unity3d ui特效制作 编辑:程序博客网 时间:2024/05/17 08:33

      这道题我们抽象成基本模型,问题就是给你一个开始全是1的序列,然后有2个操作,1是将一个位置的值 xor 1,2是询问x这个位置最左边的连续1的位置和最右边连续1的位置。我们可以怎么做呢?感觉一般的数据结构不太好弄,即使可以也要套一个二分什么的,那么我们可以考虑分块来做,我们将其分成根号n块,对于每一块,我们维护一个flag[i],flag[i]=1表示第i块全部是1,否则表示存在0,那么对于一次修改操作,我们只需要用根号n的时间维护flag[i],对于一次查询操作,我们先将x到x所在块的右区间扫一遍,如果发现0就返回,否则我们开始看x所在块的下一块的flag值,如果flag[i]=1,跳到下一块,否则暴力的扫找到1的位置,这样每次查询的复杂度也是根号n的,这样我们就能在m根号n的时间内解决,而且常数非常小。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 200005 const int block=224;int a[maxn],L[450],R[450],b[maxn],cnt,n,m,last[maxn],tot;bool flag[450];int queryl(int x){int temp=x-1;for (int i=x-1;i>=L[b[x]];i--) if (a[i]!=1) return temp-i;x=L[b[x]]-1;while (flag[b[x]]&&x>0) x=L[b[x]]-1;if (x<=0) return temp;for (int i=x;i>=L[b[x]];i--) if (a[i]!=1) return temp-i;}int queryr(int x){int temp=x;for (int i=x;i<=R[b[x]];i++) if (a[i]!=1) return i-temp;x=R[b[x]]+1;while (flag[b[x]]&&x<=n) x=R[b[x]]+1;if (x>n) return n+1-temp;for (int i=x;i<=R[b[x]];i++) if (a[i]!=1) return i-temp;}void change(int x,int y){a[x]=y;bool ok=1;for (int i=L[b[x]];i<=R[b[x]];i++) {if (a[i]!=1) {ok=0;break;}}if (ok) flag[b[x]]=1;else flag[b[x]]=0;}int main(){scanf("%d",&n);for (int i=1;i<=n;i++) a[i]=1;for (int i=1;i<=n;i++) {b[i]=(i-1)/block+1;if (b[i]!=b[i-1]) L[b[i]]=i,R[b[i-1]]=i-1;}L[1]=1;R[b[n]]=n;for (int i=1;i<=b[n];i++) {bool ok=1;for (int j=L[i];j<=R[i];j++)if (a[j]!=1) {ok=0;break;}if (ok) flag[i]=1;}scanf("%d",&m);for (int i=1;i<=m;i++) {char opt[3];int x;scanf("%s",opt);if (opt[0]=='R') {change(last[tot],1);tot--;continue;}scanf("%d",&x);if (opt[0]=='D') {change(x,0);last[++tot]=x;}if (opt[0]=='Q') if (a[x]==0) printf("0\n");else printf("%d\n",queryl(x)+queryr(x));}return 0;}


0 0
原创粉丝点击