ZJU 2301 Color the Ball
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2301
/**/
/*
题意:
给出N(N <= 2000)组操作,每组操作的形式如下:
A B C: 将[A,B]区间内的颜色染成C,C可以是白色或者黑色,序列开始
是全黑色的,并且范围在int范围内,问染色完毕后最长的白色序列。
解法:
线段树+离散化
思路:
线段树染色问题,我的做法比较麻烦,如果直接用离散化会简单许多
,但是这题是练习线段树的好题,它同样涉及到了lazy思想。因为要求得
区间内最长的白色序列,线段树的字段里面必须保存和这个长度有关的信
息,我的域如下:
int Color; // 当前区间的颜色
int lMax; // 包含左区间的连续白色的最大值时的最右端点
int rMax; // 包含右区间的连续白色的最大值时的最左端点
int MaxLR[2]; // 当前结点管辖区间的最优值的区间
int l, r; // 当前结点管理的左右区间
我们用以下函数从左右儿子中得到当前结点的信息:
void UpdateBy(Tree* ls, Tree* rs);
之所以把它写成函数是因为这里的处理比较麻烦,很容易出错,并且需要
调用多次,这个函数的作用就是通过左右儿子的信息填充本身的信息。
信息一多,处理的时候就要极为小心,因为很容易出错,Color字段其实是
充当了lazy标记的作用,用于染色的时候将它专递到子树。
[l, lMax]组成了当前结点的包含左闭区间的最优解。
[rMax, r]组成了当前结点的包含右闭区间的最优解。
[MaxLR[0], MaxLR[1]] 则是当前区间的最优解。
这样我们就可以通过传递性在儿子结点的属性都得知的情况下将父亲的值
计算出来,最后递归到根结点。具体的计算过程可以自己画棵树看一下,
在计算MaxLR的时候稍微麻烦一点。
*/
#include < iostream >
#include < cstring >
#include < algorithm >
#include < cstdio >
#include < vector >
using namespace std;
#define MUTIPLE_COLOR -1
#define BLACK 0
#define WHITE 1
#define maxn 8200
#define ul unsigned int
struct point {
int l, r;
char color;
point() {}
point(int _l, int _r, char _c) {
l = _l;
r = _r;
color = _c;
}
} ;
vector < point > pt;
int n;
ul tmp[maxn], tmpsize;
ul bin[maxn], size;
void Process() {
sort(tmp, tmp + tmpsize);
bin[ size = 1 ] = tmp[0];
for(int i = 1; i < tmpsize; i++) {
if(tmp[i] != tmp[i-1])
bin[ ++size ] = tmp[i];
}
}
int Binary( int v) {
int l = 1;
int r = size;
while(l <= r) {
int m = (l + r) >> 1;
if(bin[m] == v)
return m;
if(v > bin[m])
l = m + 1;
else
r = m - 1;
}
}
struct Tree {
int Color; // 当前区间的颜色
int lMax; // 包含左区间的连续白色的最大值时的最右端点
int rMax; // 包含右区间的连续白色的最大值时的最左端点
int MaxLR[2]; // 当前结点管辖区间的最优值的区间
int l, r;
int son[2];
char lVal, rVal;
void clear() {
son[0] = son[1] = -1;
AssignColor(BLACK);
}
int len() {
return r - l + 1;
}
void AssignColor(int nColor);
void TranslateToSon();
void WhiteProcess();
void BlackProcess();
void UpdateBy(Tree* ls, Tree* rs);
void MaxVal(int xl, int xr);
} T[maxn * 3 ];
int root, tot;
int MMax( int a, int b) {
return a > b ? a : b;
}
int GetID( int & root, int l, int r) {
if(root == -1) {
root = tot++;
T[root].l = l;
T[root].r = r;
T[root].clear();
}
return root;
}
void Tree::WhiteProcess() {
lMax = r;
rMax = l;
MaxLR[0] = l;
MaxLR[1] = r;
}
void Tree::BlackProcess() {
lMax = l - 1;
rMax = r + 1;
MaxLR[0] = -1;
MaxLR[1] = -1;
}
void Tree::AssignColor( int nColor) {
Color = nColor;
if(nColor == MUTIPLE_COLOR)
return ;
if(Color == WHITE) {
WhiteProcess();
}else if(Color == BLACK){
BlackProcess();
}
lVal = rVal = Color;
}
void Tree::TranslateToSon() {
if(Color != MUTIPLE_COLOR) {
int mid = (l + r) >> 1;
int i0 = GetID(son[0], l, mid);
T[i0].AssignColor(Color);
int i1 = GetID(son[1], mid+1, r);
T[i1].AssignColor(Color);
Color = MUTIPLE_COLOR;
}
}
void Tree::MaxVal( int xl, int xr) {
if(xl != -1 && xl <= xr) {
bool con = (MaxLR[0] == -1)
|| (bin[xr] - bin[xl] > bin[ MaxLR[1] ] - bin[ MaxLR[0] ])
|| (bin[xr] - bin[xl] == bin[ MaxLR[1] ] - bin[ MaxLR[0] ] && bin[xl] < bin[MaxLR[0]]);
if(con) {
MaxLR[0] = xl;
MaxLR[1] = xr;
}
}
}
void Tree::UpdateBy(Tree * ls, Tree * rs) {
lVal = ls->lVal;
rVal = rs->rVal;
lMax = (ls->lMax==ls->r) ? rs->lMax : ls->lMax;
rMax = (rs->rMax==rs->l) ? ls->rMax : rs->rMax;
if(ls->Color == rs->Color) {
Color = ls->Color;
}else
Color = MUTIPLE_COLOR;
MaxLR[0] = MaxLR[1] = -1;
MaxVal(l, lMax);
MaxVal(rMax, r);
MaxVal(ls->rMax, rs->lMax);
MaxVal(ls->MaxLR[0], ls->MaxLR[1]);
MaxVal(rs->MaxLR[0], rs->MaxLR[1]);
}
void Insert( int & root, int nl, int nr, int l, int r, int val) {
if(nl > r || nr < l)
return ;
GetID(root, l, r);
if(T[root].Color == val)
return ;
if(nl <= l && r <= nr) {
T[root].AssignColor(val);
return ;
}
T[root].TranslateToSon();
int mid = (l + r) >> 1;
Insert(T[root].son[0], nl, nr, l, mid, val);
Insert(T[root].son[1], nl, nr, mid + 1, r, val);
T[root].UpdateBy(&T[ T[root].son[0] ], &T[ T[root].son[1] ]);
}
int main() {
int i;
int a, b;
char str[10];
while(scanf("%d", &n) != EOF) {
tmpsize = 0;
pt.clear();
for(i = 0; i < n; i++) {
scanf("%d %d %s", &a, &b, str);
tmp[ tmpsize++ ] = a - 1;
tmp[ tmpsize++ ] = a;
tmp[ tmpsize++ ] = b;
tmp[ tmpsize++ ] = (ul)b + 1;
pt.push_back(point(a, b, str[0]=='w' ? WHITE : BLACK));
}
Process();
root = -1;
tot = 0;
Insert(root, 1, size, 1, size, BLACK);
for(i = 0; i < n; i++) {
int l = Binary(pt[i].l);
int r = Binary(pt[i].r);
Insert(root, l, r, 1, size, pt[i].color);
}
if(T[root].MaxLR[0] == -1)
printf("Oh, my god\n");
else {
printf("%d %d\n", bin[ T[root].MaxLR[0] ], bin[ T[root].MaxLR[1] ]);
}
}
return 0;
}
/**/ /*
3
1 100000 w
2 6 b
100 1000 b
*/
题意:
给出N(N <= 2000)组操作,每组操作的形式如下:
A B C: 将[A,B]区间内的颜色染成C,C可以是白色或者黑色,序列开始
是全黑色的,并且范围在int范围内,问染色完毕后最长的白色序列。
解法:
线段树+离散化
思路:
线段树染色问题,我的做法比较麻烦,如果直接用离散化会简单许多
,但是这题是练习线段树的好题,它同样涉及到了lazy思想。因为要求得
区间内最长的白色序列,线段树的字段里面必须保存和这个长度有关的信
息,我的域如下:
int Color; // 当前区间的颜色
int lMax; // 包含左区间的连续白色的最大值时的最右端点
int rMax; // 包含右区间的连续白色的最大值时的最左端点
int MaxLR[2]; // 当前结点管辖区间的最优值的区间
int l, r; // 当前结点管理的左右区间
我们用以下函数从左右儿子中得到当前结点的信息:
void UpdateBy(Tree* ls, Tree* rs);
之所以把它写成函数是因为这里的处理比较麻烦,很容易出错,并且需要
调用多次,这个函数的作用就是通过左右儿子的信息填充本身的信息。
信息一多,处理的时候就要极为小心,因为很容易出错,Color字段其实是
充当了lazy标记的作用,用于染色的时候将它专递到子树。
[l, lMax]组成了当前结点的包含左闭区间的最优解。
[rMax, r]组成了当前结点的包含右闭区间的最优解。
[MaxLR[0], MaxLR[1]] 则是当前区间的最优解。
这样我们就可以通过传递性在儿子结点的属性都得知的情况下将父亲的值
计算出来,最后递归到根结点。具体的计算过程可以自己画棵树看一下,
在计算MaxLR的时候稍微麻烦一点。
*/
#include < iostream >
#include < cstring >
#include < algorithm >
#include < cstdio >
#include < vector >
using namespace std;
#define MUTIPLE_COLOR -1
#define BLACK 0
#define WHITE 1
#define maxn 8200
#define ul unsigned int
struct point {
int l, r;
char color;
point() {}
point(int _l, int _r, char _c) {
l = _l;
r = _r;
color = _c;
}
} ;
vector < point > pt;
int n;
ul tmp[maxn], tmpsize;
ul bin[maxn], size;
void Process() {
sort(tmp, tmp + tmpsize);
bin[ size = 1 ] = tmp[0];
for(int i = 1; i < tmpsize; i++) {
if(tmp[i] != tmp[i-1])
bin[ ++size ] = tmp[i];
}
}
int Binary( int v) {
int l = 1;
int r = size;
while(l <= r) {
int m = (l + r) >> 1;
if(bin[m] == v)
return m;
if(v > bin[m])
l = m + 1;
else
r = m - 1;
}
}
struct Tree {
int Color; // 当前区间的颜色
int lMax; // 包含左区间的连续白色的最大值时的最右端点
int rMax; // 包含右区间的连续白色的最大值时的最左端点
int MaxLR[2]; // 当前结点管辖区间的最优值的区间
int l, r;
int son[2];
char lVal, rVal;
void clear() {
son[0] = son[1] = -1;
AssignColor(BLACK);
}
int len() {
return r - l + 1;
}
void AssignColor(int nColor);
void TranslateToSon();
void WhiteProcess();
void BlackProcess();
void UpdateBy(Tree* ls, Tree* rs);
void MaxVal(int xl, int xr);
} T[maxn * 3 ];
int root, tot;
int MMax( int a, int b) {
return a > b ? a : b;
}
int GetID( int & root, int l, int r) {
if(root == -1) {
root = tot++;
T[root].l = l;
T[root].r = r;
T[root].clear();
}
return root;
}
void Tree::WhiteProcess() {
lMax = r;
rMax = l;
MaxLR[0] = l;
MaxLR[1] = r;
}
void Tree::BlackProcess() {
lMax = l - 1;
rMax = r + 1;
MaxLR[0] = -1;
MaxLR[1] = -1;
}
void Tree::AssignColor( int nColor) {
Color = nColor;
if(nColor == MUTIPLE_COLOR)
return ;
if(Color == WHITE) {
WhiteProcess();
}else if(Color == BLACK){
BlackProcess();
}
lVal = rVal = Color;
}
void Tree::TranslateToSon() {
if(Color != MUTIPLE_COLOR) {
int mid = (l + r) >> 1;
int i0 = GetID(son[0], l, mid);
T[i0].AssignColor(Color);
int i1 = GetID(son[1], mid+1, r);
T[i1].AssignColor(Color);
Color = MUTIPLE_COLOR;
}
}
void Tree::MaxVal( int xl, int xr) {
if(xl != -1 && xl <= xr) {
bool con = (MaxLR[0] == -1)
|| (bin[xr] - bin[xl] > bin[ MaxLR[1] ] - bin[ MaxLR[0] ])
|| (bin[xr] - bin[xl] == bin[ MaxLR[1] ] - bin[ MaxLR[0] ] && bin[xl] < bin[MaxLR[0]]);
if(con) {
MaxLR[0] = xl;
MaxLR[1] = xr;
}
}
}
void Tree::UpdateBy(Tree * ls, Tree * rs) {
lVal = ls->lVal;
rVal = rs->rVal;
lMax = (ls->lMax==ls->r) ? rs->lMax : ls->lMax;
rMax = (rs->rMax==rs->l) ? ls->rMax : rs->rMax;
if(ls->Color == rs->Color) {
Color = ls->Color;
}else
Color = MUTIPLE_COLOR;
MaxLR[0] = MaxLR[1] = -1;
MaxVal(l, lMax);
MaxVal(rMax, r);
MaxVal(ls->rMax, rs->lMax);
MaxVal(ls->MaxLR[0], ls->MaxLR[1]);
MaxVal(rs->MaxLR[0], rs->MaxLR[1]);
}
void Insert( int & root, int nl, int nr, int l, int r, int val) {
if(nl > r || nr < l)
return ;
GetID(root, l, r);
if(T[root].Color == val)
return ;
if(nl <= l && r <= nr) {
T[root].AssignColor(val);
return ;
}
T[root].TranslateToSon();
int mid = (l + r) >> 1;
Insert(T[root].son[0], nl, nr, l, mid, val);
Insert(T[root].son[1], nl, nr, mid + 1, r, val);
T[root].UpdateBy(&T[ T[root].son[0] ], &T[ T[root].son[1] ]);
}
int main() {
int i;
int a, b;
char str[10];
while(scanf("%d", &n) != EOF) {
tmpsize = 0;
pt.clear();
for(i = 0; i < n; i++) {
scanf("%d %d %s", &a, &b, str);
tmp[ tmpsize++ ] = a - 1;
tmp[ tmpsize++ ] = a;
tmp[ tmpsize++ ] = b;
tmp[ tmpsize++ ] = (ul)b + 1;
pt.push_back(point(a, b, str[0]=='w' ? WHITE : BLACK));
}
Process();
root = -1;
tot = 0;
Insert(root, 1, size, 1, size, BLACK);
for(i = 0; i < n; i++) {
int l = Binary(pt[i].l);
int r = Binary(pt[i].r);
Insert(root, l, r, 1, size, pt[i].color);
}
if(T[root].MaxLR[0] == -1)
printf("Oh, my god\n");
else {
printf("%d %d\n", bin[ T[root].MaxLR[0] ], bin[ T[root].MaxLR[1] ]);
}
}
return 0;
}
/**/ /*
3
1 100000 w
2 6 b
100 1000 b
*/