BZOJ 2333 棘手的操作(线段树)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2333

题意:

BZOJ 2333 棘手的操作(线段树)_第1张图片

思路:离线处理。首先将所有U操作进行,得到一个DFS序列。那么中间操作都是操作的一段区间。然后用线段树维护就好了。




struct node
{
    char op[5];
    int x,v;
};


node Q[N];


int f[N];


int get(int x)
{
    if(f[x]!=x) f[x]=get(f[x]);
    return f[x];
}


int n,m,d[N];


int end[N],next[N],pos[N];


void init()
{
    RD(n);
    int i,x,y;
    FOR1(i,n) RD(d[i]);
    FOR1(i,n) end[i]=next[i]=f[i]=i;
    RD(m);
    FOR1(i,m)
    {
        RD(Q[i].op);
        if(Q[i].op[0]=='U') 
        {
            RD(Q[i].x,Q[i].v);
            x=get(Q[i].x);
            y=get(Q[i].v);
            if(x>y) swap(x,y);
            f[y]=x;
            next[end[x]]=y;
            end[x]=end[y];
        }
        else if(Q[i].op[0]=='F')
        {
            if(Q[i].op[1]!='3') RD(Q[i].x);
        }
        else
        {
            if(Q[i].op[1]=='3') RD(Q[i].x);
            else RD(Q[i].x,Q[i].v);
        }
    }
    
    clr(end,0);
    int cnt=0;
    FOR1(i,n) 
    {
        x=i;
        while(!end[x])
        {
            pos[x]=end[x]=++cnt;
            f[x]=x;
            x=next[x];
        }
    }
    FOR1(i,n) next[i]=d[i];
    FOR1(i,n) d[pos[i]]=next[i];
}




struct NODE
{
    int L,R,det,Max;
    
    void add(int x)
    {
        det+=x;
        Max+=x;
    }
};




NODE a[N<<2];


void pushUp(int t)
{
    if(a[t].L==a[t].R) return;
    a[t].Max=max(a[t*2].Max,a[t*2+1].Max);
}


void pushDown(int t)
{
    if(a[t].L==a[t].R) return;
    if(a[t].det)
    {
        a[t*2].add(a[t].det);
        a[t*2+1].add(a[t].det);
        a[t].det=0;
    }
}




void build(int t,int L,int R)
{
    a[t].det=0;
    a[t].L=L;
    a[t].R=R;
    if(L==R)
    {
        a[t].Max=d[L];
        return;
    }
    int M=(L+R)>>1;
    build(t*2,L,M);
    build(t*2+1,M+1,R);
    pushUp(t);
}


void update(int t,int L,int R,int x)
{
    if(L==a[t].L&&R==a[t].R)
    {
        a[t].add(x);
        return;
    }
    pushDown(t);
    int M=(a[t].L+a[t].R)>>1;
    if(R<=M) update(t*2,L,R,x);
    else if(L>M) update(t*2+1,L,R,x);
    else update(t*2,L,M,x),update(t*2+1,M+1,R,x);
    pushUp(t);
}


int query(int t,int L,int R)
{
    if(a[t].L==L&&a[t].R==R) return a[t].Max;
    pushDown(t);
    int M=(a[t].L+a[t].R)>>1;
    if(R<=M) return query(t*2,L,R);
    if(L>M) return query(t*2+1,L,R);
    return max(query(t*2,L,M),query(t*2+1,M+1,R));
}


int main()
{
    init();
    build(1,1,n);
    int i,x,y;
    char c;
    FOR1(i,m)
    {
        if(Q[i].op[0]=='U')
        {
            x=get(Q[i].x);
            y=get(Q[i].v);
            if(x>y) swap(x,y);
            f[y]=x;
            end[x]=end[y];
        }
        else if(Q[i].op[0]=='A')
        {
            c=Q[i].op[1];
            if(c=='1') update(1,pos[Q[i].x],pos[Q[i].x],Q[i].v);
            else if(c=='2') 
            {
                x=get(Q[i].x);
                update(1,pos[x],end[x],Q[i].v);
            }
            else update(1,1,n,Q[i].x);
        }
        else
        {
            c=Q[i].op[1];
            if(c=='1') PR(query(1,pos[Q[i].x],pos[Q[i].x]));
            else if(c=='2') 
            {
                x=get(Q[i].x);
                PR(query(1,pos[x],end[x]));
            }
            else PR(query(1,1,n));
        }
    }
}

你可能感兴趣的:(线段树)