zoukankan      html  css  js  c++  java
  • Codeforces Gym 100803G Flipping Parentheses 线段树+二分

    Flipping Parentheses

    题目连接:

    http://codeforces.com/gym/100803/attachments

    Description

    A string consisting only of parentheses ‘(’ and ‘)’ is called balanced if it is one of the following.

    • A string “()” is balanced.

    • Concatenation of two balanced strings are balanced.

    • When a string s is balanced, so is the concatenation of three strings “(”, s, and “)” in this
    order.

    Note that the condition is stronger than merely the numbers of ‘(’ and ‘)’ are equal. For instance,
    “())(()” is not balanced.

    Your task is to keep a string in a balanced state, under a severe condition in which a cosmic ray
    may flip the direction of parentheses.

    You are initially given a balanced string. Each time the direction of a single parenthesis is
    flipped, your program is notified the position of the changed character in the string. Then,
    calculate and output the leftmost position that, if the parenthesis there is flipped, the whole
    string gets back to the balanced state. After the string is balanced by changing the parenthesis
    indicated by your program, next cosmic ray flips another parenthesis, and the steps are repeated
    several times

    Input

    The input consists of a single test case formatted as follows.

    The first line consists of two integers N and Q (2 ≤ N ≤ 300000, 1 ≤ Q ≤ 150000). The second
    line is a string s of balanced parentheses with length N. Each of the following Q lines is an
    integer qi (1 ≤ qi ≤ N) that indicates that the direction of the qi-th parenthesis is flipped.

    Output

    For each event qi

    , output the position of the leftmost parenthesis you need to flip in order to
    get back to the balanced state.
    Note that each input flipping event qi
    is applied to the string after the previous flip qi−1 and its
    fix.

    Sample Input

    6 3

    ((()))

    4

    3

    1

    Sample Output

    2

    2

    1

    Hint

    题意

    给你一个平衡的括号序列,然后每次询问是让一个括号掉转方向,让你找到一个最左边的,改变方向之后能够使得序列平衡的括号

    强制在线(就是每次询问完之后,保持修改

    题解:

    把(想成1,)想成-1,平衡的显然就是前缀和为0

    对于(改成)的,我们就找到最左边的)改成(就好了

    对于)改成(的,我们就找到前缀和到结尾的最小值,大于等于2的第一个括号就好了

    为什么呢?

    因为我们维护的是前缀和,(改成)很显然是要-2的,所以我们只需要找到前缀和到结尾的最小值大于2的就好了,这样修改之后,也保持了平衡

    我们用线段树+二分来解决

    n(logn+logn)的和nlognlogn 的都比较好想

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef int SgTreeDataType;
    struct treenode
    {
        int L , R  ;
        SgTreeDataType sum , lazy;
        SgTreeDataType now;
        void updata(SgTreeDataType v)
        {
            sum += v;
            lazy += v;
        }
    };
    
    treenode tree[300005*4];
    
    void push_down(int o)
    {
        SgTreeDataType lazyval = tree[o].lazy;
    	tree[2*o].updata(lazyval) ; tree[2*o+1].updata(lazyval);
    	tree[o].lazy = 0;
    }
    
    void push_up(int o)
    {
    	tree[o].sum = min(tree[2*o].sum , tree[2*o+1].sum);
    }
    
    void build_tree(int L , int R , int o)
    {
    	tree[o].L = L , tree[o].R = R, tree[o].lazy = 0;
    	tree[o].now = 1e9;
    	tree[o].sum = 0;
    	if (R > L)
    	{
    		int mid = (L+R) >> 1;
    		build_tree(L,mid,o*2);
    		build_tree(mid+1,R,o*2+1);
    	}
    }
    
    void updata_pre(int QL,int QR,SgTreeDataType v,int o)
    {
    	int L = tree[o].L , R = tree[o].R;
    	if (QL <= L && R <= QR) tree[o].updata(v);
    	else
    	{
    		push_down(o);
    		int mid = (L+R)>>1;
    		if (QL <= mid) updata_pre(QL,QR,v,o*2);
    		if (QR >  mid) updata_pre(QL,QR,v,o*2+1);
    		push_up(o);
    	}
    }
    
    void updata_idx(int QL,int QR,SgTreeDataType v,int o)
    {
    	int L = tree[o].L , R = tree[o].R;
    	if (QL <= L && R <= QR)tree[o].now = v;
    	else
    	{
    		int mid = (L+R)>>1;
    		if (QL <= mid) updata_idx(QL,QR,v,o*2);
    		if (QR >  mid) updata_idx(QL,QR,v,o*2+1);
    		tree[o].now = min(tree[o*2].now , tree[o*2+1].now);
    	}
    }
    
    SgTreeDataType query(int QL,int QR,int o)
    {
    	int L = tree[o].L , R = tree[o].R;
    	if (QL <= L && R <= QR) return tree[o].sum;
    	else
    	{
    		push_down(o);
    		int mid = (L+R)>>1;
    		SgTreeDataType res = 1e9;
    		if (QL <= mid) res = min(res,query(QL,QR,2*o));
    		if (QR > mid) res = min(res,query(QL,QR,2*o+1));
    		push_up(o);
    		return res;
    	}
    }
    SgTreeDataType query2(int QL,int QR,int o)
    {
    	int L = tree[o].L , R = tree[o].R;
    	if (QL <= L && R <= QR) return tree[o].now;
    	else
    	{
    		int mid = (L+R)>>1;
    		SgTreeDataType res = 1e9;
    		if (QL <= mid) res = min(res,query2(QL,QR,2*o));
    		if (QR > mid) res = min(res,query2(QL,QR,2*o+1));
    		return res;
    	}
    }
    char str[300005];
    int sum[300005];
    
    int main()
    {
        int n,q;
        scanf("%d%d",&n,&q);
        scanf("%s",str+1);
        build_tree(1,n,1);
        for(int i=1;i<=n;i++)
        {
            if(str[i]=='(')
            {
                updata_pre(i,n,1,1);
                updata_idx(i,i,1,1);
            }
            else
            {
                updata_pre(i,n,-1,1);
                updata_idx(i,i,-1,1);
            }
        }
    
        while(q--)
        {
            int x;
            scanf("%d",&x);
            if(str[x]=='(')
            {
                str[x]=')';
                updata_idx(x,x,-1,1);
                updata_pre(x,n,-2,1);
                int l = 1,r = x;
                while(l<=r)
                {
                    int mid = (l+r)/2;
                    if(query2(1,mid,1)<0)r=mid-1;
                    else l=mid+1;
                }
                printf("%d
    ",l);
                updata_idx(l,l,1,1);
                updata_pre(l,n,2,1);
                str[l]='(';
            }
            else if(str[x]==')')
            {
                str[x]='(';
                updata_idx(x,x,1,1);
                updata_pre(x,n,2,1);
                int l = 1,r = x;
                while(l<=r)
                {
                    int mid = (l+r)/2;
                    if(query(mid,x,1)>=2)r=mid-1;
                    else l=mid+1;
                }
                printf("%d
    ",l);
                updata_idx(l,l,-1,1);
                updata_pre(l,n,-2,1);
                str[l]=')';
            }
            //printf("%s
    ",str+1);
        }
    }
  • 相关阅读:
    Delphi中WebBrowser自动填表模板
    对TMemoryStream的一些改进(用到了LockFile)
    用Delphi画圆角Panel的方法(使用CreateRoundRectRgn创造区域,SetWindowRgn显示指定区域)
    Delphi5的System.pas只有11514行
    《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
    Delphi动态申请数组内存的方法(不使用SetLength,采用和C相似的方式)
    Delphi的类型转换 good
    New 和 GetMem 的不同之处
    XML SelectSingleNode的使用 根据节点属性获取该节点
    ADO面板上的控件简介
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5143789.html
Copyright © 2011-2022 走看看