假設某大學有一面文化牆,各個學院都可以在上面塗色,要求塗色區域高必須和牆一樣,寬度任意但必須是整數(以公尺為單位)。塗色可以覆蓋其他學院的塗色。現在若干個學院塗色之後最終這面牆上能看見多少種顏色。
這就是簡單的染色問題了。當然有很多種不同的說法,但整體上離不開這兩個問題:1.區域覆蓋。2.多種染色方式。既然是區域操作,那麼用線段樹是比較合理了。用陣列也可以,但是資料規模稍微大一點就會tle。
當然,跟染色問題一同存在的還有就是離散化,很多部落格也是將這兩者一起來寫的,並且主要是離散化。但我個人感覺染色問題對理解線段樹很有幫助(當然還是太菜了= =大佬們都認為難點是線段樹的離散化),所以就單獨拿出來了。
線段樹有多種表現形式,感覺很多人都是拿結構體寫的,博主是用陣列寫的,其本質還是一樣的**有些不一樣而已。
整體上,我們對一段資料建成線段樹,那麼區域染色的時候就類似與修改區間。而線段樹的精髓就是利用lazy陣列,可以保證不遍歷到子結點就可以獲得區域的情況。那麼染色也要利用這個性質,對於一段區間,我們想要在上層結點上來表示出來。那麼我們可以設定3個變數:-1 表示當前區段有多種顏色,具體有多少種不用管。0表示當前區域未染色。正整數表示當前區域染了單一染色,並且顏色號是這個正整數。
所以除了特殊要求,一般我們用int來表示顏色種類(就算題目是char型別或者string,我們也可以變成int,最多寫乙個hash,還是整數方便)。那麼看下面這個例子:
這是按照上面的要求寫的線段樹,-1表示當前段有多種顏色,1表示當前段全部是1。這裡左邊,乙個1乙個0,而上面結點仍然是-1。這是因為預設把0也當成一種顏色了,可以節省**,實際在查詢的時候我們只用排除0就可以得到正確答案。
總之,這樣建立的線段樹可以表示區域染色的大致情況。而具體有多少種顏色需要在查詢的時候進行操作。
#include#include#includeusing namespace std;
#define ll long long
const long int maxn=2e5+10;
int a[maxn*4];
int tree[maxn*4];
int color[40];
int lazy[maxn*4];
int n,t,colors;
int ans;
//0 表示沒染色,-1表示雜,正整數表示該種的純色 //本題目要求剛開始全為1
void pushup(int rt)
else
tree[rt]=-1; ///-1表示雜的顏色
}void build(int l,int r,int rt)
int m=(l+r)/2;
build(l,m,rt*2);
build(m+1,r,rt*2+1);
pushup(rt);
}void pushdown(int rt,int llen,int rlen) ///這道題不是長度了
}void update(int l,int r,int rt,int l,int r,int c)
int m=(l+r)/2;
pushdown(rt,m-l+1,r-m);
if(l<=m) update(l,m,rt*2,l,r,c); 死迴圈一定是**小地方寫錯了
if(mh)
update(1,n,1,g,h,j);
} else if(str[0]=='p')
query(1,n,1,g,h);
printf("%d\n",ans);memset(color,0,sizeof(color));
} }
}return 0;
}
POJ2777 線段樹染色
初始顏色均為1,倆操作 修改 將 l,r 染為顏色z 查詢 l,r 的不同顏色數 1e5個點,1e5個操作,30種顏色 查詢 如果查詢維護區間顏色數,不滿足區間加法 顏色數較少,維護區間顏色狀態s val pushup 當前子樹s 左子樹s 右子樹s 修改 維護顏色替換標記lazy 注意pushdo...
poj2528 線段樹離散染色)
思路 l,r範圍很大,需要離散化,離散化時注意排序後如果相鄰兩個數字則可以賦相鄰的值,如果二者之間差大於一這需要賦值相差2,例如1 10為紅色,1 2為綠色,9 10為藍色,正確答案為3.include include includeusing namespace std const int n 1...
線段樹典型例題 poj2828
逆序處理。注意到如果逆序插入,則每次插入的位置都是第x個空位。所以可以用線段樹來尋找第x個合法位置 include include include include include using namespace std const int n 200005 int sum n 3 pos n val...