POJ 2777 线段树

题目大意:
有一个长度为L的木板,在上面可以涂t种颜色,有p个操作,操作可以是将a-b涂成c的颜色,也可以是询问a-b有多少种不同的颜色,对每次询问输出答案。

#include<iostream>
#include<stdio.h>
#include<string.h>
#define maxn 100000
using namespace std;
struct TREE{
    int left,right;
    int color;
}t[maxn*4+10];
bool vis[40]; //记录颜色是否出现过 

//建树 
void buildtree(int root,int left,int right){
    t[root].left=left;
    t[root].right=right;
    t[root].color=1;  //初始化,对于底层节点表示该点的颜色为1;对于非底层节点则表示该节点对应的所有颜色均为1 
    if(left==right)
        return;
    int mid=(right+left)/2;
    buildtree(root*2,left,mid);
    buildtree(root*2+1,mid+1,right);
}

//更新 
//t[root]==0 表示该节点对应的区间颜色不单一 
//t[root]!=0 表示该节点对应的区间颜色单一,且为t[root]的值 
//始终牢记线段树的更新是从根节点开始的 即从上向下更新,直到更新到想要的区间才停止更新 
void update(int root,int left,int right,int color){ //更新时注意保留原始的更新区间 
    if(t[root].left==left&&t[root].right==right){ //如果某节点的区间刚好等于想要更新的区间 
        t[root].color=color;                      //将该点的颜色进行更新,并不再向下更新 
        return;
    }
    if(t[root].color==color) return;  //如果某节点的颜色更好等于想要更新的颜色,不再向下更新(优化,不写也能过) 
    if(t[root].color){                //如果该区间颜色单一 
        t[root*2].color=t[root].color;  //更新下面节点的颜色 
        t[root*2+1].color=t[root].color;
        t[root].color=0;              //该点的颜色设置为不单一 
    }

    int mid=(t[root].left+t[root].right)/2;
    if(right<=mid) update(root*2,left,right,color);  //别写成update(root*2,left,mid+1,color) 这样的话是把左边的都更新了 
    else if(left>mid) update(root*2+1,left,right,color);
    else{
        update(root*2,left,mid,color);            //这两个区间合并起来是left-right 
        update(root*2+1,mid+1,right,color); 
    }
} 

//询问 
void query(int root,int begin,int end){  //询问时注意保留原始的询问区间 
        if(t[root].color){    //如果该点对应的区间下为单一颜色 
            vis[t[root].color]=1;   //标记该颜色出现过 
            return;                //不继续向下找了 
        }
    int mid=(t[root].left+t[root].right)/2;
    if(end<=mid) query(root*2,begin,end);
    else if(begin>mid) query(root*2+1,begin,end);
    else{
        query(root*2,begin,mid);query(root*2+1,mid+1,end);
    }   
}
int main(){
    int l,T,p,i,j;
    while(scanf("%d%d%d",&l,&T,&p)!=EOF){
        buildtree(1,1,l);
        for(j=1;j<=p;j++){
            getchar(); //注意 
            char ch;
            scanf("%c",&ch);
            int a,b,c;
            scanf("%d%d",&a,&b);
            if (a>b)
                    swap(a,b);
            if(ch=='P'){
                memset(vis,0,sizeof(vis));
                int sum=0;          
                query(1,a,b);
                for(i=1;i<=T;i++)
                    if(vis[i]==1){
                        sum++;
                    }                       
                printf("%d\n",sum);
            }
            if(ch=='C'){
                scanf("%d",&c);
                update(1,a,b,c);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值