pku 2777(经典线段树染色问题)

Count Color
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 41202   Accepted: 12458

Description

Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:

1. "C A B C" Color the board from segment A to segment B with color C.
2. "P A B" Output the number of different colors painted between segment A and segment B (including).

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.

Input

First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains "C A B C" or "P A B" (here A, B, C are integers, and A may be larger than B) as an operation defined previously.

Output

Ouput results of the output operation in order, each line contains a number.

Sample Input

2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2

Sample Output

2
1

题目意思:给三个数n,t,m n代表区间大小,t代表颜色的种类(没什么用) m代表询问次数 操作为'C'时代表更新区间值,操作为'Q'时代表询问区间内的颜色数目并输出。

运用了lazy思想和位运算 。。看了别人的思想打出来的代码。。对理解线段树真的十分有用
lazy:只要插入的区间完全覆盖了当前结点所管理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。
下次如果遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。好处就是满足条件时就不用更新到子节点,节约时间。
位运算:用二进制来表示每一位的颜色(能够想出来的人真的要对算法非常了解,,,渣渣膜拜)比如说左边叶子节点被染成了3,右边的被染成了4
则 父亲节点就被两种颜色染过了 00...0100 | 00...1000 = 00...1100 代表此区间被 3和4所染过了 ,这题颜色最多30种,所以能够用 int表示
更多解释下面见代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#define N 1100005
using namespace std;

const int MAXSIZE = 100005;
int sum;
struct Tree{
    int color; ///用二进制表示30种颜色,所以求每两个子区间的位或的结果就是父亲结点
    int cover ;///表示某区间的颜色是否相同
}tree[MAXSIZE<<2];
void pushUp(int i){
    tree[i].color = tree[i<<1].color|tree[i<<1|1].color;
}
void pushDown(int i){
    if(tree[i].cover==1){
        tree[i<<1].color = tree[i].color;
        tree[i<<1|1].color = tree[i].color;
        tree[i<<1].cover = tree[i<<1|1].cover = 1;
        tree[i].cover = 0;
    }
}
void build(int l,int r,int idx){
    tree[idx].color = 1; ///刚开始颜色都为1
    tree[idx].cover = 1;  ///刚开始区间颜色都是相同的
    if(l==r) return ;
    int mid = (l+r)>>1;
    build(l,mid,idx<<1);
    build(mid+1,r,idx<<1|1);
    pushUp(idx);
}

void update(int l,int r,int L,int R,int idx,int val){
    if(l>=L&&R>=r){
        tree[idx].cover = 1;
        tree[idx].color=val;
        return;
    }
    pushDown(idx);
    int mid = (l+r)>>1;
    if(mid>=L) update(l,mid,L,R,idx<<1,val);
    if(mid<R)  update(mid+1,r,L,R,idx<<1|1,val);
    pushUp(idx);
}
void query(int l,int r,int L,int R,int idx){
    if(l>=L&&R>=r){
        sum|=tree[idx].color;
        return;
    }
    pushDown(idx);
    int mid = (l+r)>>1;
    if(mid>=L) query(l,mid,L,R,idx<<1);
    if(mid<R)  query(mid+1,r,L,R,idx<<1|1);
}
int solve(){
    int ans = 0;
    while(sum){
        if(sum&1)  ///如果sum的最低位是1则证明已经被染色
            ans++;
        sum = sum>>1;
    }
    return ans;
}

int main()
{
    int n,t,m;
    while(scanf("%d%d%d",&n,&t,&m)!=EOF){
        build(1,n,1);
        while(m--){
            char s[5];
            scanf("%s",s);
            if(s[0]=='C'){
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                if(a>b) swap(a,b);
                update(1,n,a,b,1,1<<(c-1));  ///以二进制来表示颜色,比如染色成2 则二进制为00..010 即 2^1(^代表次方)
            }else{
                int a,b;
                sum = 0;
                scanf("%d%d",&a,&b);
                if(a>b) swap(a,b);
                query(1,n,a,b,1);
                printf("%d
",solve());
            }
        }
    }
    return 0;
}


原文地址:https://www.cnblogs.com/liyinggang/p/5304085.html