线段树_poj_2777

题意

  • 题目链接: http://poj.org/problem?id=2777
  • 题意:有一个长板子,多次操作,有两种操作,第一种是给从a到b那段染一种颜色c,另一种是询问a到b有多少种不同的颜色。输入别用cin

思路

  1. 结构体node存放左右端点l, r,和染色id(num表示);num > 0; 表示这一部分[l, r]染成num色, num = 11, 表示[l, r]有多种颜色

  2. built()老规矩建树,初始颜色都为1; update(),不用更新到最底层,更新[l, r]的区间颜色,这里有一个lazy思想,从根节点更新区间,如果这个区间染色后将会有多种颜色就往子节点跟新,两个左右子节点继承父节点的颜色, 父节点的颜色为-1; query():由于所有区间一种颜色num大于0, 多种颜色num小于0, 所以判断tree【node】.num,为-1,就继续查询,不为-1,就直接标记。

代码

#include<iostream>
#include<cstring>

using namespace std;
const int maxn = 100010;
bool vis[35];
struct{
    int l, r;
    int num;
}tree[maxn << 2];

void built(int s, int e, int node){

    tree[node].l = s;
    tree[node].r = e;
    tree[node].num = 1;
    int mid = (s + e) >> 1;
    if(s == e){
        return ;
    }
    built(s, mid, node << 1);
    built(mid + 1, e, node << 1 | 1);
}
void down(int node){

    if(tree[node].num != -1){//如果[l,r],一种颜色,更新后出现两种颜色下传父节点颜色给子节点
        tree[node << 1].num = tree[node].num;
        tree[node << 1 | 1].num = tree[node].num;
        tree[node].num = -1; 
    }
}
void update(int L, int R, int node, int num){

    if(tree[node].l >= L && tree[node].r <= R){
        tree[node].num = num;
        return ;
    }
   else{
       if(tree[node].num != num) down(node);
       int mid = (tree[node].l + tree[node].r) >> 1;
       if(mid < L) update(L, R, node << 1 | 1, num);
       else if(mid >= R) update(L, R, node << 1, num);
       else{
           update(mid | 1, R, node << 1 | 1, num);
           update(L, mid, node << 1, num);
       }
   }
}
int query(int L, int R, int node){

    if(tree[node].num != -1){
        vis[tree[node].num] = true;//用一个数组来标记
        return 1;
    }
    int mid = (tree[node].l + tree[node].r) >> 1;
    if(L > mid){
        query(L, R, node << 1 | 1);
    }else if(R <= mid){
       query(L, R, node << 1);
    }else{
        query(L, mid, node << 1);
        query(mid + 1, R, node << 1 | 1);
    }
}
int main(){
    int n, t, o;
    char ctr;
    int l, r, num;
    while(cin >> n >> t >> o){
        built(1, n, 1);
        while(o --){//线段树切忌用cin   scanf才不会超时
            cin >> ctr;
            if(ctr == 'C'){
                scanf("%d%d%d", &l, &r, &num);
                if(l > r) update(r, l, 1, num);
                else update(l, r, 1, num);
            }else{
                 scanf("%d%d", &l, &r);
                memset(vis, false, sizeof(vis));
                if(l > r) query(r, l, 1);
                else query(l ,r, 1);
                int ans = 0;
                for(int i = 1; i <= t; i++){
                    ans += vis[i];
                }
                cout << ans << endl;
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值