POJ 2777 Count Color 線段樹入門題

畫船聽雨發表於2014-02-19

今天開始看的線段樹,感覺樹儲存的優勢了啊,很強大、時間複雜度降低了很多啊。

在這裡先說一下題目的大體意思是:給區間進行染色,後染的顏色會會覆蓋掉之前染過的顏色,然後輸入C是代表給區間(a,b)染色成c。P代表輸出區間(a,b)一共有幾種顏色。

典型的線段樹的建立、修改、與查詢問題啊。所以要用線段樹來做啊、否則會超時的啊,我好像跑了969ms,有點龜速了啊,但是重點是學習演算法,優化以後熟悉了再說吧。

PS:這是線段樹,第一題。

Count Color
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 32820   Accepted: 9889

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

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-7
#define M 10001000
//#define LL __int64
#define LL long long
#define INF 0x3f3f3f3f
#define PI 3.1415926535898

const int maxn = 100100;
using namespace std;

struct node
{
    int a, b;
    int color;
    int ct;
} f[4*maxn];
int n, t, k;
int cnum[maxn];
int ans;

void creat(int l, int r, int num)
{
    f[num].a = l;
    f[num].b = r;
    f[num].color = (1<<1);//初始化顏色;
    f[num].ct = 0;
    int mid = (l+r)/2;
    if(r-l>=1)
    {
        creat(l, mid, 2*num);//遞迴建立線段樹;
        creat(mid+1, r, 2*num+1);
    }
}

void Insert(int l, int r, int c, int num)
{
    int a = f[num].a;
    int b = f[num].b;
    if(a == l && r == b)//遞迴的出口,就是找到了這個區間;
    {
        f[num].color = cnum[c];
        f[num].ct = c;
        return;
    }
    int mid = (a+b)/2;
    if(f[num].ct != 0)//如果根節點被染過,就用它的子節點儲存顏色,然後就把它自己的顏色去掉;
    {
        f[num*2].ct = f[num].ct;
        f[num*2].color = f[num].color;
        f[num*2+1].ct = f[num].ct;
        f[num*2+1].color = f[num].color;
        f[num].ct = 0;
    }
    if(mid >= r)
    {
        Insert(l, r, c, num*2);//偏左;
    }
    else if(mid < l)
    {
        Insert(l, r, c, num*2+1);//偏右;
    }
    else
    {
        Insert(l, mid, c, num*2);//中間分開的;
        Insert(mid+1, r, c, num*2+1);
    }
    f[num].color = f[num*2].color|f[num*2+1].color;
}

void Search(int l, int r, int num)
{
    int a = f[num].a;
    int b = f[num].b;
    int mid = (a+b)/2;
    if(l <= f[num].a && f[num].b <= r)
    {
        ans = ans|f[num].color;//找到滿足的區間然後標記顏色;
        return ;
    }
    else if((f[num].a <= l && r <= f[num].b) && f[num].ct != 0)
    {
        ans = ans|f[num].color;
        return ;
    }
    if(mid >= r)
    {
        Search(l, r, num*2);
    }
    else if(mid < l)
    {
        Search(l, r, num*2+1);
    }
    else
    {
        Search(l, mid, num*2);
        Search(mid+1, r, num*2+1);
    }
}

int dos(int x)
{
    int sum = 0;
    for(int i = 1; i <= 30; i++)
    {
        if((x&(1 << i)) != 0)
            sum ++;
    }
    return sum;
}

int main()
{
    int i;
    for(i = 1; i <= 30; i++)
        cnum[i] = (1<<i);
    while(cin >>n>>t>>k)
    {
        creat(1, n, 1);
        int a, b, c;
        char str;
        while(k--)
        {
            cin >>str;
            if(str == 'C')
            {
                cin >>a>>b>>c;
                if(a > b) swap(a, b);
                Insert(a, b, c, 1);
            }
            else if(str == 'P')
            {
                cin >>a>>b;
                if(a > b) swap(a, b);
                ans = 0;
                Search(a, b, 1);
                cout<<dos(ans)<<endl;
            }
        }
    }
    return 0;
}


相關文章