HDU5997 【线段树】

思路:

用vector存一下各种颜色的区间,每次处理颜色的区间,相同颜色不需要更新。区间最多1e6个没错,但是随着颜色的更替区间只会越来越少。

维护区间左右两端的颜色,lazy一下。

区间合并的时候 sum= sum_left + sum_right , 如果左儿子的区间右边和右儿子的区间左边颜色相同 sum--。

复杂度:don't know;

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

struct Seg{
    int Sum;
    int Lazy;
    int Left,Right;
    int Left_Color,Right_Color;
}q[N*4];

struct asd{
    int Left,Right;
};
vector<asd>eg[1000000+10];
int col[N];

void Pushdown(int num)
{
    if(q[num].Lazy==-1) return;
    q[num<<1].Lazy=q[num<<1|1].Lazy=q[num].Lazy;
    q[num<<1].Sum=q[num<<1|1].Sum=1;
    q[num<<1].Left_Color=q[num<<1].Right_Color=q[num].Lazy;
    q[num<<1|1].Left_Color=q[num<<1|1].Right_Color=q[num].Lazy;
    q[num].Lazy=-1;
}

void Build(int num,int Left,int Right)
{
    q[num].Left=Left;q[num].Right=Right;q[num].Lazy=-1;
    if(Left == Right){
        q[num].Sum=1;
        q[num].Left_Color=q[num].Right_Color=col[Left];
        return;
    }
    int Mid=(Left+Right)>>1;
    Build(num<<1,Left,Mid);
    Build(num<<1|1,Mid+1,Right);
    q[num].Left_Color=q[num<<1].Left_Color;
    q[num].Right_Color=q[num<<1|1].Right_Color;
    if(q[num<<1].Right_Color == q[num<<1|1].Left_Color)
        q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum-1;
    else
        q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
}

int Query(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right) return q[num].Sum;
    Pushdown(num);

    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right)
        return Query(num<<1,Left,Right);
    else if(Mid<Left)
        return Query(num<<1|1,Left,Right);
    else{
        int ans=0;
        ans+=Query(num<<1,Left,Mid);
        ans+=Query(num<<1|1,Mid+1,Right);
        if(q[num<<1].Right_Color == q[num<<1|1].Left_Color) ans--;
        return ans;
    }
}

void Update(int num,int Left,int Right,int Color)
{
    if(Left<=q[num].Left && q[num].Right<=Right){
        q[num].Lazy=Color;
        q[num].Sum=1;
        q[num].Left_Color=q[num].Right_Color=Color;
        return;
    }
    Pushdown(num);

    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right)
        Update(num<<1,Left,Right,Color);
    else if(Mid<Left)
        Update(num<<1|1,Left,Right,Color);
    else
    {
        Update(num<<1,Left,Mid,Color);
        Update(num<<1|1,Mid+1,Right,Color);
    }
    q[num].Left_Color=q[num<<1].Left_Color;
    q[num].Right_Color=q[num<<1|1].Right_Color;
    q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
    if(q[num<<1].Right_Color == q[num<<1|1].Left_Color) q[num].Sum--;
}

void init(int n)
{
    for(int i=0;i<=1000000;i++)
        eg[i].clear();

    asd temp;
    int Color,Pre_Color=-1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&Color);
        col[i]=Color;
        if(Pre_Color==-1){
            temp.Left=i;
            Pre_Color=Color;
        }
        else if(Pre_Color!=Color){
            temp.Right=i-1;
            eg[Pre_Color].push_back(temp);
            temp.Left=i;
            Pre_Color=Color;
        }
    }
    temp.Right=n;
    eg[Pre_Color].push_back(temp);

    Build(1,1,n);
}

void solve(int n)
{
    asd temp;
    int Left,Right,x,y;
    int op;
    while(n--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            if(x==y) continue;

            int sz=eg[x].size();
            for(int i=0;i<sz;i++)
            {
                temp=eg[x][i];
                Update(1,temp.Left,temp.Right,y);
                eg[y].push_back(eg[x][i]);
            }
            eg[x].clear();
        }
        else
        {
            scanf("%d%d",&Left,&Right);
            printf("%d
",Query(1,Left,Right));
        }
    }
}

int main()
{
    int n,T,Q;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&Q);
        init(n);
        solve(Q);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777487.html