色板游戏(线段树)

色板游戏

题目背景:
阿宝上学了,今天老师拿来了一块很长的涂色板。
题目描述:
色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格。并从左到右标记为1, 2, … L。现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. “C A B C” 指在A到 B 号方格中涂上颜色 C。2. “P A B” 指老师的提问:A到 B号方格中有几种颜色。学校的颜料盒中一共有 T 种颜料。为简便起见,我们把他们标记为 1, 2, … T. 开始时色板上原有的颜色就为1号色。 面对如此复杂的问题,阿宝向你求助,你能帮助他吗?
输入输出格式:
输入格式:
第一行有3个整数 L (1 <= L <= 100000), T (1 <= T <= 30) 和 O (1 <= O <= 100000). 在这里O表示事件数, 接下来 O 行, 每行以 “C A B C” 或 “P A B” 得形式表示所要做的事情(这里 A, B, C 为整数, 可能A> B)
输出格式:
对于老师的提问,做出相应的回答。每行一个整数。
输入输出样例:
输入样例#1:
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
输出样例#1:
2
1

思路:
线段树
区间修改就是普通的修改,关键在区间查询,即如何统计出某一区间中有多少种颜色。
写一个函数:check,如果tree[tree[k].lch].color!=tree[tree[k].rch].color,则把tree[k].color设为-1,意思是这个节点左二子和右儿子的颜色不一样。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100010;
int n,m,t,tot;
bool flag[35];
struct node
{
    int l,r;
    int lch,rch;
    int flag;
    int color;
}tree[maxn*4];
char c;
int init()
{
    int f=1,p=0;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;
}
void build_tree(int ll,int rr)
{
    int cur=++tot;
    tree[cur].l=ll;
    tree[cur].r=rr;
    if(ll!=rr-1)
    {
        int mid=(ll+rr)>>1;
        tree[cur].lch=tot+1;
        build_tree(ll,mid);
        tree[cur].rch=tot+1;
        build_tree(mid,rr);
        tree[cur].color=1;
    }
    else tree[cur].color=1;
}
void update(int k)
{
    tree[tree[k].lch].color=tree[k].flag;
    tree[tree[k].rch].color=tree[k].flag;
    tree[tree[k].lch].flag=tree[k].flag;
    tree[tree[k].rch].flag=tree[k].flag;
    tree[k].flag=0;
}
void check(int k)//检查函数
{
    if(tree[tree[k].lch].color==tree[tree[k].rch].color)
    tree[k].color=tree[tree[k].lch].color;
    else tree[k].color=-1;
}
void change(int k,int l,int r,int p)
{
    if(l<=tree[k].l&&r>=tree[k].r)
    {
        tree[k].color=p;
        tree[k].flag=p;
        return;
    }
    if(tree[k].flag)
    update(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<mid) change(tree[k].lch,l,r,p);
    if(r>mid) change(tree[k].rch,l,r,p);
    check(k);
}
void find(int k,int l,int r)
{
    if(l<=tree[k].l&&r>=tree[k].r&&tree[k].color!=-1)//注意判断
    {
        flag[tree[k].color]=1;
        return;
    }
    if(tree[k].flag)
    update(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<mid) find(tree[k].lch,l,r);
    if(r>mid) find(tree[k].rch,l,r);
}
int main()
{
    int x,y,z;
    n=init();t=init();m=init();
    build_tree(1,n+1);
    for(int i=1;i<=m;i++)
    {
        cin>>c;
        if(c=='C')
        {
            x=init();y=init();z=init();
            if(x>y) swap(x,y);
            change(1,x,y+1,z);
        }
        else
        {
            memset(flag,0,sizeof(flag));
            int ans=0;
            x=init();y=init();
            if(x>y) swap(x,y);
            find(1,x,y+1);
            for(int j=1;j<=t;j++)
            if(flag[j])
            ans++;
            printf("%d\n",ans);
        }
    }
    return 0;
}
posted @ 2016-09-11 20:48  抽空的太阳  阅读(146)  评论(0编辑  收藏  举报