Flipping Parentheses

题目来源:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=138130

输入:

6 3
((()))
4
3
1

输出:

2
2
1

题意:输入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   6
 ( (   )  ) ) )

a: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
//找第一次')'
时间: 2024-10-06 12:10:51

Flipping Parentheses的相关文章

CSU - 1542 Flipping Parentheses (线段树)

CSU - 1542 Flipping Parentheses Time Limit: 5000MS   Memory Limit: 262144KB   64bit IO Format: %lld & %llu Submit Status Description Input Output Sample Input 6 3 ((())) 4 3 1 Sample Output 2 2 1 Hint 题意:先给出一个符合括号匹配的字符串,然后Q次操作 每次操作将某个括号反转,问将哪个括号反转能使字

CSU 1542 Flipping Parentheses(线段树)

1542: Flipping Parentheses Time Limit: 5 Sec  Memory Limit: 256 MB Submit: 289  Solved: 79 [Submit][Status][Web Board] Description Input Output Sample Input 6 3 ((())) 4 3 1 Sample Output 2 2 1 HINT 题目大意: 给出一个长度为n的已经匹配的括号字符串,然后有Q次操作,每次操作会翻转一个括号,让你翻转最

leetcode22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 这个问题解的个

Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" class S

#22 Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 本题是括号匹配

【leetcode】Generate Parentheses

题目: 给定整数n,返回n对匹配的小括号字符串数组. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 分析: 这种问题的模式是:1)问题的解有多个 ,2)每个解都是由多个有效的 "步骤" 组成的,3)变更以有解的某个或某些"步骤"

LeetCode 241. Different Ways to Add Parentheses

241. Different Ways to Add Parentheses Add to List Description Submission Solutions Total Accepted: 38849 Total Submissions: 92740 Difficulty: Medium Contributors: Admin Given a string of numbers and operators, return all possible results from comput

leetcode 20 Valid Parentheses

class Solution { public: bool isValid(string s) { stack<char> parentheses; for (int i = 0; i < s.size(); ++i) { if (s[i] == '(' || s[i] == '[' || s[i] == '{') parentheses.push(s[i]); else { if (parentheses.empty()) return false; if (s[i] == ')' &

22. Generate Parentheses——本质:树,DFS求解可能的path

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: [ "((()))", "(()())", "(())()", "()(())", "()()()" ] cla