Sereja has a bracket sequence s1, s2, ..., sn, or, in other words, a string s of length n, consisting of characters "(" and ")".
Sereja needs to answer m queries, each of them is described by two integers li, ri (1 ≤ li ≤ ri ≤ n). The answer to the i-th query is the length of the maximum correct bracket subsequence of sequence sli, sli + 1, ..., sri. Help Sereja answer all queries.
You can find the definitions for a subsequence and a correct bracket sequence in the notes.
The first line contains a sequence of characters s1, s2, ..., sn (1 ≤ n ≤ 106) without any spaces. Each character is either a "(" or a ")". The second line contains integer m (1 ≤ m ≤ 105) — the number of queries. Each of the next m lines contains a pair of integers. The i-th line contains integers li, ri (1 ≤ li ≤ ri ≤ n) — the description of the i-th query.
Print the answer to each question on a single line. Print the answers in the order they go in the input.
())(())(())( 7 1 1 2 3 1 2 1 12 8 12 5 11 2 10
0 0 2 10 4 6 6
A subsequence of length |x| of string s = s1s2... s|s| (where |s| is the length of string s) is string x = sk1sk2... sk|x| (1 ≤ k1 < k2 < ... < k|x| ≤ |s|).
A correct bracket sequence is a bracket sequence that can be transformed into a correct aryphmetic expression by inserting characters "1" and "+" between the characters of the string. For example, bracket sequences "()()", "(())" are correct (the resulting expressions "(1)+(1)", "((1+1)+1)"), and ")(" and "(" are not.
For the third query required sequence will be «()».
For the fourth query required sequence will be «()(())(())».
题目大意:
一共有两种操作:
①1 x,在数组最后端加一个数x。
②2 x,y 重复数组中前x个数y次加在数组最后端。
求最后N个询问位子上的数。保证输入都是合法的。
思路:
1、首先观察到,对应第二种操作只会重复数组前100000位子上的数,那么我们首先预处理:
①暴力预处理出前100000位子上的数,记录到ans【i】中。
②维护一个数组sum【i】表示一直进行操作到第i次,整个数组现在的长度。
2、对应每次查询,考虑到随着操作次数的增多,数组的整个长度一定在增大这个单调性,那么我们考虑对长度进行二分。
对应二分过程中有很多细节(列举不全大家的地方参考代码):
对应当前枚举的二分值mid:
①如果sum【mid-1】<=x&&sum【mid】>=x,那么对应我们处理解:
如果a【mid】.op==1(操作1),那么对应output=a【mid】.x;
如果a【mid】.op==2(操作2),那么对应output=ans【(x-sum[mid-1])%a[mid].x】;
(只是我代码挫写的不好的附加产物的样纸----------------->)并且我们记录当前解,注意这里不能记录一次解之后就break掉,因为有可能出现连续的两个操作1的情况,会出现偏差,那么对应我们r=mid-1,记录最小的位子mid时候的解.
②对应如果不是上述情况,如果此时sum【mid】>x,那么对应r=mid-1,否则l=mid+1.
对应一直二分下去,每次有可行解的时候都进行记录,输出最后的可行解。
3、因为数据范围都不小,会有爆int的地方,图方便,我全部将int替换成了LL,各位强迫症看官不要打我啊QWQ
Ac代码(代码君:我是挫逼但我很萌!):
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll __int64
struct node
{
ll op;
ll x,y;
}a[1000500];
ll m;
ll sum[1050000];
ll ans[1020000];
void init()
{
for(ll i=0;i<m;i++)
{
ll sumpre;
if(i==0)sumpre=0;
else sumpre=sum[i-1];
if(a[i].op==1)sum[i]=1+sumpre;
else
{
ll tmp=(ll)a[i].x;
ll tmp2=(ll)a[i].y;
sum[i]=sumpre+tmp*tmp2;
}
}
ll now=1;
for(ll i=0;i<m;i++)
{
if(a[i].op==1)
{
ans[now++]=a[i].x;
if(now>100050)break;
}
else
{
for(ll j=0;j<a[i].y;j++)
{
for(ll k=1;k<=a[i].x;k++)
{
ans[now++]=ans[k];
if(now>100050)break;
}
if(now>100050)break;
}
}
}
}
int main()
{
while(~scanf("%I64d",&m))
{
memset(sum,0,sizeof(sum));
memset(ans,-1,sizeof(ans));
for(ll i=0;i<m;i++)
{
scanf("%I64d",&a[i].op);
if(a[i].op==1)
{
scanf("%I64d",&a[i].x);
}
if(a[i].op==2)
{
scanf("%I64d%I64d",&a[i].x,&a[i].y);
}
}
init();
ll q;
scanf("%I64d",&q);
while(q--)
{
ll x;
scanf("%I64d",&x);
ll l=0;
ll r=m-1;
ll output;
while(r-l>=0)
{
ll mid=(l+r)/2;
if(x==sum[mid]||(mid-1>=0&&x<=sum[mid]&&x>=sum[mid-1]))
{
if(a[mid].op==1)
{
output=a[mid].x;
r=mid-1;
}
else
{
ll pos=(x-sum[mid-1])%a[mid].x;
if(pos==0)pos=a[mid].x;
output=ans[pos];
r=mid-1;
}
continue;
}
if(x<sum[mid])
{
r=mid-1;
}
else l=mid+1;
}
printf("%I64d ",output);
}
printf("\n");
}
}
/*
4
1 1
1 2
2 2 100000
2
*/