POJ2777 线段树区间染色问题

 

 

题意:给L长度的木板,给T种颜色,给O个操作,每次可以选择一段区间染色,或查询一个区间的颜色种类

思路1:用叶节点存具体颜色,父节点记录子节点的颜色集合(都采用二进制从低位到高位表示具体颜色数字)

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn=1e5+10;
int l,t,o;
struct note
{
    int left,right,sum,lazy;
    void up(int val)
    {
        sum=1<<(val-1);
        lazy=val;
    }
} tree[maxn*4];
void pushup(int id)
{
    tree[id].sum=tree[id<<1].sum|tree[id<<1|1].sum;
}
void pushdown(int id)
{
    if(tree[id].lazy)
    {
        tree[id<<1].up(tree[id].lazy);
        tree[id<<1|1].up(tree[id].lazy);
        tree[id].lazy=0;
    }
}

void build(int id,int l,int r)
{
    tree[id].left=l;
    tree[id].right=r;
    if(l==r)
        tree[id].sum=1;
    else
    {
        int mid=(l+r)/2;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
        pushup(id);
    }
}
int query(int id,int l,int r)
{
    if(l<=tree[id].left&&tree[id].right<=r)
        return tree[id].sum;
    pushdown(id);
    int mid=(tree[id].left+tree[id].right)/2;
    int ans=0;
    if(l<=mid) ans|=query(id<<1,l,r);
    if(r>mid) ans|=query(id<<1|1,l,r);
    return ans;
}

void update(int id,int l,int r,int val)
{
    if(l<=tree[id].left&&tree[id].right<=r)
    {
        tree[id].up(val);
        return;
    }
    pushdown(id);
    int mid=(tree[id].left+tree[id].right)/2;
    if(l<=mid) update(id<<1,l,r,val);
    if(r>mid) update(id<<1|1,l,r,val);
    pushup(id);
}

int main()
{
    int l,t,o;
    scanf("%d%d%d",&l,&t,&o);
    build(1,1,l);
    for(int i=1; i<=o; i++)
    {
        getchar();
        char op;
        scanf("%c",&op);
        if(op=='C')
        {
            int l,r,val;
            if(l>r)
                swap(l,r);
            scanf("%d%d%d",&l,&r,&val);
            update(1,l,r,val);
        }
        else
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if(l>r)
                swap(l,r);
            int sum=query(1,l,r);
            int ans=0;
            while(sum>0)
            {
                if(sum&1) ans++;
                sum=sum>>1;
            }
            printf("%d\n",ans);
        }
    }
}

 

 

思路2:用线段树叶节点记录颜色所代表的数字,父节点为-1表示两个子节点颜色不相同,>0时的数字代表子节点全为这个数字对应颜色。

 

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn=1e5+10;
int a[maxn];
int l,t,o;
int vis[35];
struct note
{
    int left,right,sum,lazy;
    void up(int val)
    {
        sum=val;
        lazy=val;
    }
} tree[maxn*4];
void pushup(int id)
{
    if(tree[id<<1].sum==-1||tree[id<<1|1].sum==-1)
        tree[id].sum=-1;
    else if(tree[id<<1].sum==tree[id<<1|1].sum)
        tree[id].sum=tree[id<<1].sum;
    else
        tree[id].sum=-1;
}
void pushdown(int id)
{
    if(tree[id].lazy)
    {
        tree[id<<1].up(tree[id].lazy);
        tree[id<<1|1].up(tree[id].lazy);
        tree[id].lazy=0;
    }
}

void build(int id,int l,int r)
{
    tree[id].left=l;
    tree[id].right=r;
    if(l==r)
        tree[id].sum=1;
    else
    {
        int mid=(l+r)/2;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
        pushup(id);
    }
}
void query(int id,int l,int r)
{
    if(tree[id].sum!=-1)
    {
        vis[tree[id].sum]=1;
        return;
    }
//    pushdown(id);
    int mid=(tree[id].left+tree[id].right)/2;
    if(l<=mid) query(id<<1,l,r);
    if(r>mid) query(id<<1|1,l,r);
}
void update(int id,int l,int r,int val)
{
    if(l<=tree[id].left&&tree[id].right<=r)
    {
        tree[id].up(val);
        return;
    }
    pushdown(id);
    int mid=(tree[id].left+tree[id].right)/2;
    if(l<=mid) update(id<<1,l,r,val);
    if(r>mid) update(id<<1|1,l,r,val);
    pushup(id);
}


int main()
{
    scanf("%d%d%d",&l,&t,&o);
    build(1,1,l);
    for(int i=1; i<=o; i++)
    {
        char op;
        getchar();
        scanf("%c",&op);
        if(op=='C')
        {
            int l,r,color;
            scanf("%d%d%d",&l,&r,&color);
            update(1,l,r,color);
        }
        else
        {
            int l,r;
            scanf("%d%d",&l,&r);
            memset(vis,0,sizeof(vis));
            query(1,l,r);
            int ans=0;
            for(int i=1; i<=30; i++)
            {
                if(vis[i])
                    ans++;
            }
            printf("%d\n",ans);
        }
    }
}

 

posted @ 2019-10-03 16:38  paranoid。  阅读(326)  评论(0编辑  收藏  举报