Flipping Parentheses
来源:互联网 发布:js解析xml文件的作用 编辑:程序博客网 时间:2024/05/22 09:48
题目来源:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=138130
输入:
6 3((()))431
输出:221
题意:输入n,q (2<n<300000,1<q<150000)
第二行再输入长度为n(下标从1开始)的字符串,只含‘(’和‘)’,且是匹配好的。
再输入q个下标查询。问改变输入下标位置的字符,如‘(’-->‘)’ 或者‘)’->‘(’
求改变一个字符,使字符串全部匹配(必须从左端找出一个)。
例:
1 2 3 4 5 6
( ( ( ) ) )
输入4变成:
1 2 3 4 5 6
( ( ( ( ) )
改变下标为2的字符,变成:
思路:1 2 3 4 5 6( )( ( ) )
字符串又变成匹配的。
1、利用左+,右-,a
(1)第一种情况‘)’->'('
1 2 3 4 5 6 ( ( ( ) ) )
a:1 2 3 2 1 0
输入4变成:
1 2 3 4 5 6( ( ( ( ) )
a: 1 2 3 4 3 2
结论:从上图可以看出在改变值4开始每次都+2
(2)第二种情况‘(’->‘)’
1 2 3 4 5 6( ( ( ) ) )a:1 2 3 2 1 0输入3变成:1 2 3 4 5 6a:1 2 1 0 -1 -2( ( ) ) ) )结论:从上图可以看出在改变值3开始每次都-2
2、每次查询,改变之后,整个字符串都更新了一遍。因此联想到利用线段树来查询,更新
3、查找能使整个字符串恢复到匹配状态。(通过验证,找规律)(1)如果输入的是‘)’->'(',就要找从最左边查找,查找字符为‘(’的下标。方法:从最左边查找,当a数组>=2的位置时,就算已经找到了。(2)如果输入的是‘(’->')',就要从最左边查找们第一次出现的‘)’。方法:要算出f数组,f数组=a数据-下标;从最左边查找,当f数组为>0,就算已经找到了。
#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>using namespace std;const int MAXN=300010;char s[MAXN];int sum[MAXN];struct Node{int a,f,s;}tree[MAXN*4];int MIN(int x,int y) {return x>y?y:x;}int fun(int i){ return s[i]=='('?1:-1;}void buildtree(int u,int L,int R)//建树{ tree[u].s=0; if(L==R) { tree[u].f=sum[L]-L; tree[u].a=sum[L]; return ; } int mid=(L+R)/2; buildtree(u<<1,L,mid); buildtree((u<<1)+1,mid+1,R); tree[u].f=MIN(tree[u<<1].f,tree[(u<<1)+1].f); tree[u].a=MIN(tree[u<<1].a,tree[(u<<1)+1].a);}void get_down(int u)//延迟更新{ tree[u<<1].s+=tree[u].s; tree[u<<1].a+=tree[u].s; tree[u<<1].f+=tree[u].s; tree[(u<<1)+1].s+=tree[u].s; tree[(u<<1)+1].a+=tree[u].s; tree[(u<<1)+1].f+=tree[u].s; tree[u].s=0;}void update(int u,int L,int R,int x,int add)//更新{ if(x<=L) { tree[u].s+=add; tree[u].f+=add; tree[u].a+=add; return ; } get_down(u); int mid=(L+R)/2; if(x<=mid) update(u<<1,L,mid,x,add);//左侧可能需要更新 update((u<<1)+1,mid+1,R,x,add);//右侧是一定要更新的 tree[u].f=MIN(tree[u<<1].f,tree[(u<<1)+1].f); tree[u].a=MIN(tree[u<<1].a,tree[(u<<1)+1].a);}//查询从len往前查询,最后一个<2的位置+1,也就是从左边第一个>=2 的位置int query1(int u,int L,int R){ if(L==R) return L+1; int mid=(L+R)/2; get_down(u); if(tree[(u<<1)+1].a<2) query1((u<<1)+1, mid+1, R); else query1((u<<1),L,mid);}int query2(int u,int L,int R)//查询最左边第一次出现')'的位置{ if(L==R) return L; int mid=(L+R)/2; get_down(u); if(tree[u<<1].f<0) query2(u<<1,L,mid); else query2((u<<1)+1,mid+1,R);}int main(){ int i,t,n,m,x,y,len; while(scanf("%d%d\n",&t,&n)==2) { s[0]='0'; memset(sum,0,sizeof(sum)); scanf("%s",s+1); len=strlen(s)-1; for(i=1;i<=len;i++) sum[i]=sum[i-1]+fun(i); buildtree(1,1,len); for(i=1;i <=n;i++) { scanf("%d",&x); s[x]=(s[x]=='(' ? ')' : '('); if(s[x]=='(') update(1,1,len,x,2); else update(1,1,len,x,-2); if(s[x]=='(') y=query1(1,1,len);//>=2,找( -> ) else y=query2(1,1,len); //找第一次出现')',)->( s[y]=(s[y]=='(' ? ')' : '('); if(s[y]=='(') update(1,1,len,y,2); else update(1,1,len,y,-2); printf("%d\n",y); } } return 0;}//1 2 3 4 5 6//( ( ( ) ) )//1 2 3 2 1 0//')'->'(' +2 4//( ( ( ( ) )//1 2 3 4 3 2//找第一次>=2 a//'('->')'-2 3//( ( ) ) ) )//1 2 1 0 -1 -2//0 0 -2 -4 -6 -8 f//找第一次')'
0 0
- Flipping Parentheses
- CSU 1542 Flipping Parentheses
- 线段树 csu1542 Flipping Parentheses
- Gym 100803G Flipping Parentheses
- Gym 100803G Flipping Parentheses
- CSU - 1542 Flipping Parentheses (线段树)
- CSU 1542 Flipping Parentheses(线段树)
- UVALive 6838Flipping Parentheses (线段树)
- Flipping Parentheses (线段树 单点更新 区间查询)
- UVALive 6838 Flipping Parentheses // 线段树 区间修改 最值查询
- 2014-2015 ACM-ICPC, Asia Tokyo Regional Contest G題:Flipping Parentheses [线段树]
- UVALive 6838 Flipping Parentheses(线段树、单点更新、区间查询)
- Flipping colors
- Flipping Game
- Flipping Game
- Bit-flipping attack
- Page Flipping and BackBuffering
- CF:A. Flipping Game
- [POJ 1195] Mobile phones · 树状数组
- Redis中key-value实现
- C++刷题——2713: 函数---求x的y次方
- 递归函数详解
- 【ThinkingInJava】54、对List操作中本质的部分进行测试还有Queue中的操作测试性能比较
- Flipping Parentheses
- 猫猫学iOS(四十九)多线程网络之线程的创建NSThreand
- 破解office13VOL
- Web端服务器推送技术原理分析及dwr框架简单的使用
- 【ThinkingInJava】55、对set中的操作测试性能比较
- 【ThinkingInJava】56、查询出文件路径下所有的文件
- 带自定义title的tabhost
- 【ThinkingInJava】57、批量修改文件的名字
- [POJ 1289] The Cat in the Hat · 数学