http://poj.org/problem?id=2777
题意:给出一个长 L 的板子,板子被分成 L 段 每段初始颜色为 1, 然后两种操作:
C l, r, color 表示将 l 到 r 的颜色修改成 color
P l, r 表示询问 l 到 r 有多少种颜色。
思路:区间操作可以用线段树或者Splay树,因为颜色不超过 30 种,所有可以用一个数的每个二进制位来表示这段里面是否有这个颜色,例如用 101 表示某一段有颜色 1 和颜色 3。
线段树(454ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 100005;
struct Tree{
int bin;
int l, r, lazy;
};
int n, m, q;
Tree tr[maxn << 2];
void BuildTree(int rt, int l, int r)
{
tr[rt].l = l;
tr[rt].r = r;
tr[rt].bin = 1;
tr[rt].lazy = 0;
if(l == r)
return ;
int mid = (l + r) >> 1;
BuildTree(rt << 1, l, mid);
BuildTree(rt << 1 | 1, mid + 1, r);
}
void PushUp(int rt)
{
if(!tr[rt].lazy)
return ;
tr[rt].bin = tr[rt].lazy;
if(tr[rt].l == tr[rt].r)
return ;
tr[rt << 1].lazy = tr[rt].lazy;
tr[rt << 1 | 1].lazy = tr[rt].lazy;
tr[rt].lazy = 0;
}
int Updata(int rt, int l, int r, int color)
{
PushUp(rt);
if(tr[rt].l > r || tr[rt].r < l)
return tr[rt].bin;
if(tr[rt].l >= l && tr[rt].r <= r){
tr[rt].lazy = color;
return tr[rt].lazy;
}
tr[rt].bin = Updata(rt << 1, l, r, color) | Updata(rt << 1 | 1, l, r, color);
return tr[rt].bin;
}
int Query(int rt, int l, int r)
{
PushUp(rt);
if(tr[rt].l > r || tr[rt].r < l)
return 0;
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].bin;
return Query(rt << 1, l, r) | Query(rt << 1 | 1, l, r);
}
int main()
{
char str[5];
int l, r, color;
while(~scanf("%d%d%d", &n, &m, &q)){
BuildTree(1, 1, n);
while(q--){
scanf("%s%d%d", str, &l, &r);
if(l > r)
swap(l, r);
if(str[0] == 'C'){
scanf("%d", &color);
Updata(1, l, r, 1 << (color - 1));
}else{
int res = 0;
int val = Query(1, l, r);
while(val){
res += (val & 1);
val >>= 1;
}
printf("%d\n", res);
}
}
}
return 0;
}
Splay(938ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 100005;
struct Tree{
int pre, chd[2];
int color, bin, lazy, Size;
void SetTree(int color, int bin, int lazy, int Size, int pre, int chd0, int chd1){
this->color = color;
this->bin = bin;
this->pre = pre;
this->lazy = lazy;
this->Size = Size;
this->chd[0] = chd0;
this->chd[1] = chd1;
}
};
int n, m, q;
Tree tr[maxn];
int F(int rt){
return tr[tr[rt].pre].chd[1] == rt;
}
void PushUp(int rt)
{
tr[tr[rt].chd[0]].pre = rt;
tr[tr[rt].chd[1]].pre = rt;
tr[rt].bin = tr[rt].color;
tr[rt].bin |= tr[tr[rt].chd[0]].bin;
tr[rt].bin |= tr[tr[rt].chd[1]].bin;
tr[rt].Size = tr[tr[rt].chd[0]].Size + tr[tr[rt].chd[1]].Size + 1;
}
void PushDown(int rt)
{
if(!tr[rt].lazy)
return ;
if(tr[rt].chd[0]){
tr[tr[rt].chd[0]].bin = tr[rt].bin;
tr[tr[rt].chd[0]].lazy = tr[rt].lazy;
tr[tr[rt].chd[0]].color = tr[rt].lazy;
}
if(tr[rt].chd[1]){
tr[tr[rt].chd[1]].bin = tr[rt].bin;
tr[tr[rt].chd[1]].lazy = tr[rt].lazy;
tr[tr[rt].chd[1]].color = tr[rt].lazy;
}
tr[rt].lazy = 0;
}
int Rotate(int rt)
{
int chd = F(rt);
int pre = tr[rt].pre;
tr[rt].pre = tr[pre].pre;
tr[tr[pre].pre].chd[F(pre)] = rt;
tr[pre].chd[chd] = tr[rt].chd[!chd];
tr[rt].chd[!chd] = pre;
PushUp(pre);
PushUp(rt);
}
int Splay(int rt, int rw)
{
while(tr[rw].pre != rt){
int pre = tr[rw].pre;
if(F(rw) != F(pre) || tr[pre].pre == rt){
Rotate(rw);
}else{
Rotate(pre);
Rotate(rw);
}
}
if(rt)
PushUp(rt);
return rw;
}
int Find(int rt, int pos)
{
PushDown(rt);
int ret = rt;
if(tr[tr[rt].chd[0]].Size == pos - 1){
ret = rt;
}else if(tr[tr[rt].chd[0]].Size >= pos){
ret = Find(tr[rt].chd[0], pos);
}else{
ret = Find(tr[rt].chd[1], pos - tr[tr[rt].chd[0]].Size - 1);
}
PushUp(rt);
return ret;
}
int BuildTree(int Size)
{
for(int i = 1; i < Size; i++){
tr[i].SetTree(1, 1, 0, Size - i + 1, i - 1, 0, i + 1);
}
tr[0].SetTree(0, 0, 0, 0, 0, 0, 0);
tr[Size].SetTree(1, 1, 0, 1, Size - 1, 0, 0);
return 1;
}
int main()
{
char str[5];
int l, r, color;
while(~scanf("%d%d%d", &n, &m, &q)){
int rt = BuildTree(n + 2);
rt = Splay(0, n + 2);
while(q--){
scanf("%s%d%d", str, &l, &r);
if(l > r)
swap(l, r);
rt = Splay(0, Find(rt, l));
Splay(rt, Find(rt, r + 2));
if(str[0] == 'C'){
scanf("%d", &color);
tr[tr[tr[rt].chd[1]].chd[0]].bin= 1 << (color - 1);
tr[tr[tr[rt].chd[1]].chd[0]].lazy = 1 << (color - 1);
tr[tr[tr[rt].chd[1]].chd[0]].color = 1 << (color - 1);
PushDown(tr[tr[rt].chd[1]].chd[0]);
PushUp(tr[rt].chd[1]);
PushUp(rt);
}else{
int res = 0;
int ans = tr[tr[tr[rt].chd[1]].chd[0]].bin;
while(ans){
res += (ans & 1);
ans >>= 1;
}
printf("%d\n", res);
}
}
}
return 0;
}

本文介绍了解决区间修改和查询问题的两种数据结构实现方法:线段树和伸展树(Splay Tree)。通过实例展示了如何使用这两种数据结构来高效处理区间内的颜色修改和颜色种类查询操作。

1293

被折叠的 条评论
为什么被折叠?



