1. 程式人生 > >POJ 2777 Count Color 線段樹

POJ 2777 Count Color 線段樹

Count Color
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 13340 Accepted: 3790

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

Source

#include<iostream>
using namespace std;
#define MAXN 100001

struct Seg_Tree   //線段樹的結構
{
    Seg_Tree *leftptr,*rightptr;//線段樹兩個子樹的指標
    int left,right,color;//兩個節點的表示範圍和節點的顏色
};

int L,T,O,cnt;//輸入的長度L,顏色的種類T和操作的數目O
int numOfTree;//樹的當前數目
Seg_Tree tree[MAXN*4],*Root; //所有的節點和根節點

Seg_Tree* CreatNode() //建立新節點
{
    Seg_Tree *p= &tree[numOfTree++];//建立一個新的指標,指向數組裡的一個元素
    memset(p,0,sizeof(Seg_Tree));
    return p;
}

Seg_Tree* CreatTree(int s,int e)//建立樹
{
    Seg_Tree* root=CreatNode();//創立結點
    root->left=s;
    root->right=e;//為左右的範圍設立值
    if(s!=e)
    {
        int mid=(s+e)/2;//遞迴分解,節點表示的範圍越來越小
        root->leftptr=CreatTree(s,mid);//子樹表示的範圍約是父節點的1/2
        root->rightptr=CreatTree(mid+1,e);
     }
     return root;
}

bool odd(int n)//判斷這個顏色是否為單色
{
    return (n&(n-1))==0;
}

void updateTree(Seg_Tree *root,int s,int e,int color)//更新線段樹
{
    if(s<=root->left&&e>=root->right)//如果此節點表示的範圍完全被包含,則整個被重新改變顏色
    {
        root->color=color;
        return;
    }
    if(root->color==color)  return;//節點顏色不需要被改變
    if(odd(root->color))  //如果節點為單色,則在上一次改變中,子樹沒有被改變,這個重新賦值
    {
        root->leftptr->color=root->color;
        root->rightptr->color=root->color;
    }
    int mid=(root->left+root->right)/2;
    if(s<=mid) updateTree(root->leftptr,s,e,color);  //如果左子樹需要被改變
    if(e>mid) updateTree(root->rightptr,s,e,color);  //右子樹被改變
    root->color=root->leftptr->color|root->rightptr->color; //父節點的顏色等於2個子樹的或和
}

void Query(Seg_Tree* root,int s,int e,int &cnt)  //查詢
{
    if(s<=root->left&&e>=root->right) //如果節點被完全包括
    {
        cnt=cnt|root->color;
        return;
    }
    if(odd(root->color))
    {
        cnt=cnt|root->color;
        return;
    }
    int mid=(root->left+root->right)/2;
    if(s<=mid) Query(root->leftptr,s,e,cnt); //查詢左子樹
    if(e>mid) Query(root->rightptr,s,e,cnt); //查詢右子樹
}

int cal(int n) //計算顏色數量
{
    int cnt=0;
    while(n>0)
    {
        if(n%2) cnt++;
        n>>=1;
    }
    return cnt;
}

int main()
{
    numOfTree=0;
    scanf("%d%d%d",&L,&T,&O);
    Root=CreatTree(1,L);
    updateTree(Root,1,L,1);
    char cmd;
    int s,e,c;
    while (O--)
    {
        scanf(" %c",&cmd);
        if(cmd=='C')
        {
            scanf("%d%d%d",&s,&e,&c);
            if(s>e) swap(s,e);
            updateTree(Root,s,e,1<<(c-1));
        }
        else
        {
            cnt=0;
            scanf("%d%d",&s,&e);
            if(s>e) swap(s,e);
            Query(Root,s,e,cnt);
            printf("%d/n",cal(cnt));
        }
    }
    //int i;cin>>i;
    return 0;
}

相關推薦

POJ 2777 Count Color 線段

Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13340 Accepted: 3790 Description Chosen Problem Solving and Pro

[日常摸魚][poj2777]Count Color-線段

記得 one div d+ pri none define hide c016 辣雞會考考完啦哈哈哈哈 題意:一塊板分成$L$塊,每次給一段連續的塊染色或者詢問一段有幾種顏色,顏色的範圍$\leq 30$ 我記得我好像做過一個類似的二維染色的問題…不過那個用樹

poj 2777 Count Color

圖片 pushd const poj string name scan tdi mes 和hdu5023一樣不過詢問不同。 #include <cstdio> #include <cstring> #include <algorit

poj2777 - Count Color - 線段+位運算+lazy思想(詳解)

http://poj.org/problem?id=2777  題意: 區間1到n,起始顏色都為1,每次更新一段區間的顏色(C left right val),問區間內的顏色有幾種(P left right) 思路: 這題給的顏色種類最多30,可以想到用位運算來求解,顏色是

poj2777--Count Color(線段&&二進位制)

連結: #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 100005; struct Segme

poj-2777(區間線段,求種類數模板)

題目連結:http://poj.org/problem?id=2777 參考文章:https://blog.csdn.net/heucodesong/article/details/81038360 題目大意:給出T中顏色,可以給一段區域塗色,初始是全為1的顏色,然後有兩種操作 (1)C x y z表示

POJ - 3321 Apple Tree (線段 + 建樹 + 思維轉換)

hup tin struct esc same branch rgb 標記 tdi POJ - 3321 Apple Tree Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %

POJ 2352 Stars(線段

pri printf ans r+ mat for ios 不能 ash 題目地址:POJ 2352 今天的周賽被虐了。。TAT..線段樹太渣了。。得好好補補了(盡管是從昨天才開始學的。。不能算補。。。) 這題還是非常easy的。。維護信息是每個橫坐標的出現的次數。 代

poj 3468 整理一下線段的寫法

ring 寫法 int nod ret sca using scanf tdi // 對於延遲更新,我們在updata 和query的時候 pushdown和pushup兩個東西都要存在 #include <iostream> #include <cst

POJ 2828 Buy Tickets(線段單點)

== fun time str 每次 cout cti sta 新的 https://vjudge.net/problem/POJ-2828 題目意思:有n個數,進行n次操作,每次操作有兩個數pos, ans。pos的意思是把ans放到第pos 位置的後面,pos後面的數就

Subsequence Count線段

ans 葉子節點 matrix scrip hid hup %d sub 相對 Time Limit: 1000 ms Memory Limit: 256 MB Description   給定一個01串 $S_{1 \cdots n}$ 和 $Q$ 個操作。

POJ 2828 Buy Tickets | 線段的喵用

ans define 發現 維護 fine build poj print n) 題意: 給你n次插隊操作,每次兩個數,pos,w,意為在pos後插入一個權值為w的數; 最後輸出1~n的權值 題解: 首先可以發現,最後一次插入的位置是準確的位置 所以這個就變成了若幹個子問

Picture POJ - 1177(掃描線 + 線段

區間 cstring pan double pen pic set sstream div 題意:求矩形並的面積。。 解析:   掃描線第一道題。。。。自下而上掃描的。。。 如果不懂什麽是掃描線 戳我 #include <iostream> #includ

POJ - 3667 Hotel(線段區間合並)

而且 algorithm ons back -- 停車場 sig 標記 efi 題目鏈接 題意: 給定一個有$N$個車位的停車場(都在一條直線上),現在有有兩種操作 $1.x $ 要停連續的停$x$輛車,輸出第一輛車停的位置(盡量靠前),不能就輸出$0$;

POJ 2828 逆向思維+線段

因為後面的人會影響去前面人的位置,(如果後面的人插在前面的人的位置,那麼前面的人的位置就會向後移動),那麼我們從後往前插入處理,這樣保證插入後不會變化。用線段樹的每個節點記錄這個區間的空位置數,每次插入的時候將這個人放在第pos[i]個空格的地方, 因為後面的人如果排在前面人的前面,那麼我

Mayor's posters 【POJ - 2528】【線段:講解離散化後TLE的原因】

題目連結   題目是一道很好的題,他用很神奇的資料告訴了我們——少用map,會TLE的。。。所以,這道題怎樣避免N*log(N)的map??我們可以換成lower_bound()來進行優化,但是在此之前可以用unique()進行去重操作(自己懶,所以用已有的STL檔案)。 &n

POJ 2828 逆向思維+線段

因為後面的人會影響去前面人的位置,(如果後面的人插在前面的人的位置,那麼前面的人的位置就會向後移動),那麼我們從後往前插入處理,這樣保證插入後不會變化。用線段樹的每個節點記錄這個區間的空位置數,每次插入的時候將這個人放在第pos[i]個空格的地方, 因為後面的人如果排在前面人

POJ 3928 Ping pong 線段

N(3<=N<=20000) ping pong players live along a west-east street(consider the street as a line segment). Each player has a unique skil

POJ 2299 Ultra-QuickSort 線段+求逆序數+離散化

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping

POJ 4047 Garden(線段

參考題解 有n個連續的一維上的點,每個點有一個美麗值。 每次有三種操作: 1、將x點的美麗值改為y。 2、將x、y交換 3、查詢[x y]間,連續k個點的美麗值總和的最大值。 這裡我是看的題解的做法,利用線段樹,葉子i表示[i i+k]美麗值總和,然後每個點維護一個區間最大值。每個位置向前取