P1558 色板游戏
题目地址
思路:位运算,状态压缩,线段树
-
分析思路
- 求某个区间的颜色集合的运算时支持 结合律的 ;
- 看到 T ≤ 30 T≤30 T≤30 能想到 状态压缩 ;
- 所以可以设置状态: X \text{X} X的二进制下的第 i \text{i} i位为 1 \text{1} 1表示有第 i \text{i} i种颜色,否则没有 ;
- 合并两个状态用到了按位或运算 ;
-
线段树
- Pushup \text{Pushup} Pushup操作直接求或运算即可
- 其他操作照常
-
Code
#include <stdio.h> #include <string.h> #define Clean(X) memset(X,0,sizeof(X)) #define LS RT*2 #define RS RT*2+1 const int MaxL = 100005 , MaxK = 30; unsigned L , K , O ; inline unsigned QRead () { unsigned X = 0; char C = getchar() ; while (C > '9' || C < '0') C = getchar() ; while (C >='0' && C <='9') { X = X * 10 + C -'0' ; C = getchar() ; } return X ; } /* 头文件和准备工作 */ unsigned Cnt(unsigned X) { unsigned Ans = 0 ; while (X) { ++Ans ; X -= (X&(-X)) ; } return Ans ; } /* Cnt函数可以统计一个数的二进制位种所含有的1的个数。 每次进行Lowbit运算,都消除了一个1和它后面的0。 */ unsigned Date[MaxL * 4] , Left[MaxL * 4] , Right [MaxL * 4] , Tag[MaxL * 4] ; void Plant (unsigned RT , unsigned L , unsigned R) { Left[RT] = L , Right[RT] = R ; Date[RT] = 1 ; Tag[RT] = 0 ; if (L == R) return ; unsigned Mid = (L + R) >> 1 ; Plant (LS , L , Mid) , Plant (RS , Mid + 1 , R) ; } inline void Spd (unsigned RT) { Tag[LS] = Tag[RS] = Date[LS] = Date[RS] = Tag[RT]; Tag[RT] = 0 ; } unsigned Ask (unsigned RT , unsigned L , unsigned R) { if (Left[RT] >= L && Right[RT] <= R) return Date[RT] ; unsigned Mid = (Left[RT] + Right[RT] ) >> 1 , Al = 0 , Ar = 0; if (Tag[RT])Spd(RT) ; if (L <= Mid) Al = Ask (LS , L , R) ; if (R > Mid) Ar = Ask (RS , L , R) ; return Al | Ar ; } void Add (unsigned RT , unsigned L , unsigned R,unsigned K) { if (Left[RT] >= L && Right[RT] <= R) { Date[RT] = Tag[RT] = K ; return ; } unsigned Mid = (Left[RT] + Right[RT] ) >> 1 ; if (Tag[RT] )Spd (RT) ; if (L <= Mid) Add (LS , L , R , K) ; if (R > Mid) Add (RS , L , R , K) ; Date[RT] = Date[LS] | Date[RS] ; } /* 线段树的基本函数 */ void Swap(unsigned int &X, unsigned int &Y) { int T = X ; X = Y ; Y = T ; } int main () { // freopen ("P1558.in" , "r" , stdin) ; L = QRead () , K = QRead () , O = QRead () ; Plant (1 , 1 , L) ; for (register unsigned i = 1 ; i <= O ; ++ i) { char C = getchar() ; while (C != 'P' && C != 'C') C = getchar() ; if (C == 'C') { unsigned L = QRead () , R = QRead () , Cl = QRead () - 1 ; if (L > R) Swap (L , R) ; Add (1 , L , R , 1 << Cl) ; } else { unsigned L = QRead () , R = QRead () ; if (L > R) Swap (L , R) ; printf ("%d\n" , Cnt (Ask (1 , L , R))); } } fclose (stdin) ; fclose (stdout); return 0; }