列表

详情


NC16737. 01串

描述

给出一个长度为n的01串S(一个由0和1组成的序列,下标为1到n的整数)
支持以下几种操作:
操作1:给出l,r,k,将01串下标为l到r的一段重复k次并放回原位;
操作2:给出l,r,k,将01串下标为l到r的一段带翻转地重复k次(具体地说,第i(1≤ i≤ k)次重复时,若i-1的二进制表示中有奇数个1,则这次重复时要左右反转,否则不变),最后放回原位;
操作3:给出l,r,将01串下标为l到r的一段删除;
操作4:给出k,求01串中从左到右第k个1的位置,若k超过01串中1的个数,则输出-1。

输入描述

第一行一个整数n
接下来一行,一个长度为n的01串
接下来一行,一个整数m
接下来m行,每行第一个整数op表示操作类型
若op=1或op=2,这一行接下来有三个整数l,r,k
若op=3,这一行接下来有两个整数l,r
若op=4,这一行输入一个k

输出描述

对每个操作4,输出一行,表示答案

示例1

输入:

11
11011100010
5
3 2 3
2 6 8 5
1 2 5 3
4 8
4 100

输出:

10
-1

说明:

第1次操作:1[10]11100010->111100010,删除了10
第2次操作:11110[001]0->11110[001,100,100,001,100]0->111100011001000011000,将001重复了5次,其中第2,3,5次是翻转的
第3次操作:1[1110]0011001000011000->1[1110,1110,1110]0011001000011000->11110111011100011001000011000,将1110重复了3次
第4次操作:111101110[1]1100011001000011000,第8个1在01串中的第10个位置
第5次操作:不存在100个1,输出-1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 670ms, 内存消耗: 416480K, 提交时间: 2018-11-16 18:05:38

#include<bits/stdc++.h>
using namespace std;

int rand_int()
{
	return RAND_MAX<=32768?rand()*32768+rand():rand();
}
const int N=1e5+5;
struct Node
{
	Node *cl,*cr;
	bool exist,val,rev;
	int sz,cnt1;
	void push_up()
	{
		sz=exist;cnt1=val;
		if(cl){sz+=cl->sz;cnt1+=cl->cnt1;}
		if(cr){sz+=cr->sz;cnt1+=cr->cnt1;}
	}
};
Node *rt,q[N*200],*tail=q;
Node *newNode(bool v)
{
	++tail;
	tail->exist=1;
	tail->cnt1=tail->val=v;
	tail->sz=1;
	return tail;
}
Node *copy(Node *x)
{
	*++tail=*x;
	return tail;
}
Node *failNode(Node *l,Node *r)
{
	++tail;
	tail->cl=l;tail->cr=r;
	tail->push_up();
	return tail;
}
void push_down(Node *x)
{
	if(x->rev)
	{
		x->rev=0;
		swap(x->cl,x->cr);
		if(x->cl)(x->cl=copy(x->cl))->rev^=1;
		if(x->cr)(x->cr=copy(x->cr))->rev^=1;
	}
}
Node *merge(Node *a,Node *b)
{
	if(!a)return b;
	if(!b)return a;
	if(rand_int()%(a->sz+b->sz)<a->sz)
	{
		push_down(a);
		a=copy(a);
		a->cr=merge(a->cr,b);
		a->push_up();
		return a;
	}
	else
	{
		push_down(b);
		b=copy(b);
		b->cl=merge(a,b->cl);
		b->push_up(); 
		return b;
	}
}
void split(Node *a,int k,Node *&l,Node *&r)
{
	if(!k){l=0;r=a;return ;}
	push_down(a);
	a=copy(a);
	int l_sz=a->cl?a->cl->sz:0;
	if(k<=l_sz)
	{
		split(a->cl,k,l,r);
		a->cl=r;
		r=a;
	}
	else
	{
		split(a->cr,k-(l_sz+a->exist),l,r);
		a->cr=l;
		l=a;
	}
	a->push_up();
}
char s[N];
Node *build(int l,int r)
{
	if(l>r)return 0;
	int mid=(l+r)/2;
	Node *x=newNode(s[mid]=='1');
	x->cl=build(l,mid-1);
	x->cr=build(mid+1,r);
	x->push_up();
	return x;
}
int query(int k)
{
	if(k>rt->cnt1)return -1;
	int ans=0;
	Node *x=rt;
	while(1)
	{
		push_down(x);
		int l_cnt1=x->cl?x->cl->cnt1:0;
		if(k<=l_cnt1)x=x->cl; else
		{
			ans+=(x->cl?x->cl->sz:0)+x->exist;
			k-=l_cnt1+x->val;
			if(!k)break;
			x=x->cr;
		}
	}
	return ans;
}

int main()
{
#ifdef kcz
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
	int n;
	cin>>n;
	scanf("%s",s+1);
	rt=build(1,n);
	int m;
	cin>>m;
	while(m--)
	{
		int op;
		scanf("%d",&op);
		if(op==4)
		{
			int k;
			scanf("%d",&k);
			printf("%d\n",query(k));
			continue;
		}
		int l,r;
		scanf("%d%d",&l,&r);
		Node *a0,*a1;
		split(rt,l-1,a0,a1);
		Node *p,*a2;
		split(a1,r-l+1,p,a2);
		if(op==3)
		{
			rt=merge(a0,a2);
			continue;
		}
		int k;
		scanf("%d",&k);
		Node *np=copy(p);
		if(op==2)np->rev^=1;
		int i=1;
		for(;i<k;i*=2)
		{
			Node *p1=failNode(p,np),*np1=failNode(np,p);
			p=p1;np=np1;
			p->push_up();
			np->push_up();
		}
		Node *pl,*pr;
		split(p,k*(r-l+1),pl,pr);
		rt=merge(a0,merge(pl,a2));
	}
}

上一题