hdu5217 线段树

题解:

考试的时候连 O ( n l o g 2 n ) 的做法都没有想出来啊,太菜了……只询问第k位是哪种括号就很简单了,直接用线段树维护就好了,对于第k位在原来的位置,其实也可以搞,就在线段树上二分一下就好了,具体如何二分呢?对于每个区间,最后消完之后一定都是若干个(加上若干个)的形式,那么从左到右(的数量是单调不减的,)也同理,那么我们可以直接二分,做到 O ( n l o g 2 n ) ,对于 O ( n l o g n ) 的做法,可以把询问包含的所有线段树的区间都拿出来,然后看具体是在哪个区间内,在哪个区间再二分,就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const int inf=2147483647;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,a[Maxn];
char s[Maxn];
struct Seg{int lc,rc,l,r,c,ll,rr;}tr[Maxn<<1];
int tot=0;
void merge(Seg &x,Seg lc,Seg rc)
{
    int t=min(lc.rr,rc.ll);
    x.c=lc.c+rc.c-2*t;
    int lll=lc.rr,rrr=rc.ll;
    lll-=t,rrr-=t;
    x.ll=lc.ll+rrr;
    x.rr=rc.rr+lll;
}
void build(int l,int r)
{
    int t=++tot;
    tr[t].l=l;tr[t].r=r;
    if(l==r)
    {
        tr[t].c=1;
        if(a[l])tr[t].ll=1,tr[t].rr=0;
        else tr[t].ll=0,tr[t].rr=1;
        return;
    }
    int mid=l+r>>1;
    tr[t].lc=tot+1,build(l,mid);
    tr[t].rc=tot+1,build(mid+1,r);
    merge(tr[t],tr[tr[t].lc],tr[tr[t].rc]);
}
void modify(int x,int p)
{
    if(tr[x].l==tr[x].r)
    {
        tr[x].ll^=1,tr[x].rr^=1;
        return;
    }
    int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
    if(p<=mid)modify(lc,p);
    else modify(rc,p);
    merge(tr[x],tr[lc],tr[rc]);
}
int pos[Maxn],lp;
void get(int x,int l,int r)
{
    if(tr[x].l==l&&tr[x].r==r){pos[++lp]=x;return;}
    int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
    if(r<=mid)get(lc,l,r);
    else if(l>mid)get(rc,l,r);
    else get(lc,l,mid),get(rc,mid+1,r);
}
int query1(int x,int k)
{
    if(tr[x].l==tr[x].r)return tr[x].l;
    int lc=tr[x].lc,rc=tr[x].rc;
    if(k<=tr[lc].ll)return query1(lc,k);
    else return query1(rc,k-tr[lc].ll+tr[lc].rr);
}
int query2(int x,int k)
{
    if(tr[x].l==tr[x].r)return tr[x].l;
    int lc=tr[x].lc,rc=tr[x].rc;
    if(k<=tr[rc].rr)return query2(rc,k);
    else return query2(lc,k-tr[rc].rr+tr[rc].ll);
}
int main()
{
    int T=read();
    while(T--)
    {
        tot=0;
        n=read(),m=read();
        scanf("%s",s+1);
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='(')a[i]=0;
            else a[i]=1;
        }
        build(1,n);
        while(m--)
        {
            int op=read();
            int l,r,x;
            if(op==2)
            {
                l=read(),r=read(),x=read();
                lp=0;
                get(1,l,r);
                Seg tmp=tr[pos[1]];
                for(int i=2;i<=lp;i++)merge(tmp,tmp,tr[pos[i]]);
                if(x>tmp.c){puts("-1");continue;}
                if(x<=tmp.ll)
                {
                    Seg t1,t2;
                    t1.ll=t1.rr=t1.c=0;t2=t1;
                    for(int i=1;i<=lp;i++)
                    {
                        merge(t1,t1,tr[pos[i]]);
                        if(t1.ll>=x)
                        {
                            printf("%d\n",query1(pos[i],x-t2.ll+t2.rr));
                            break;
                        }
                        t2=t1;
                    }
                }
                else
                {
                    x=tmp.rr-(x-tmp.ll)+1;
                    Seg t1,t2;
                    t1.ll=t1.rr=t1.c=0;t2=t1;
                    for(int i=lp;i;i--)
                    {
                        merge(t1,tr[pos[i]],t1);
                        if(t1.rr>=x)
                        {
                            printf("%d\n",query2(pos[i],x-t2.rr+t2.ll));
                            break;
                        }
                        t2=t1;
                    }
                }
            }
            else modify(1,read());
        }
    }
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/80021363