您的位置:首页 > 其它

ZOJ 1610 Count the Colors

2011-08-03 00:41 274 查看
看完线段树本来打算找这道基础题练手,但是悲惨的砸进去2个半小时。

本来打算写个线段树的总结,看来也没时间了。

改了七次才AC,ZOJ又狂抽风。泪奔。

最BT的是最后一次犯错的代码竟然是TLE掉,不禁感叹牛逼~(见注释⑦处)

另看了下别人的代码,都比较短,思路不太一样。什么情况,明天再看看~

代码烂注释,慎入

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
inline int Rint() {int x; scanf("%d", &x); return x;}

#define MAXN 8000
#define BLANK -1
#define MIX -2
struct node
{
int l, r;
//!⑥ 0也可以是颜色,不能拿来当 无色(特殊值)
int c; //color 混合=-2 无色=-1 颜色=0/1/2/3....
}a[MAXN*3]; //开3倍
//a[MAXN*2+10]; //!①注意 这里开两倍是不够的,因为一般不会是满二叉,如[0,3]

void init(int l, int r, int i) //CALL: init(0, 8000, 1);
{//i=index
a[i].c = BLANK; a[i].l = l; a[i].r = r;
if(r-l > 1) //大于1 就还要分 // if(l+1 != r) 由于是整数,这样也可以
{
int mid = (l+r)/2;
init(l, mid, i*2);
init(mid, r, i*2+1);
}
}
void clear(int i) //CALL: clear(1)
{
a[i].c = BLANK;
if(a[i].r-a[i].l >1)
{
clear(i*2);
clear(i*2+1);
}
}
void insert(int x1, int x2, int c, int i) //CALL: insert(x1, x2, c, 1)
{
if(x2 == x1) return; //点

int mid = (a[i].l+a[i].r)/2; //!④mid不事先放在node里,造成很多麻烦

if(a[i].c == c) return;
else if(x1 == a[i].l && x2 == a[i].r) //正好覆盖
{
a[i].c = c;

//★★★ ⑦ 以下这样是不行的,遍历太多,直接TLE,违背线段树初衷!
/*
//!②递归更新
if(a[i].r-a[i].l >1) //!⑤不是叶子结点,才要更新
{
insert(a[i].l, mid, c, i*2);
insert(mid, a[i].r, c, i*2+1);
}
*/
}
else
{
int oldColor = a[i].c;
a[i].c = MIX; //此区间不是单纯的色,即混合 c=-2

if(mid <= x1) //mid x1 x2
{
//printf("insert(%d, %d, %d, 右子树[%d,%d]);\n",x1, x2, c, a[i*2+1].l, a[i*2+1].r);
insert(x1, x2, c, i*2+1);

if(oldColor != BLANK && oldColor != MIX) //!⑦ 不应在完全覆盖时递归更新,而应选择在这里维护少量数据!
{
insert(a[i].l, mid, oldColor, i*2);
insert(mid, x1, oldColor, i*2+1);
insert(x2, a[i].r, oldColor, i*2+1);
}
}
else if(x2 <= mid) //x1 x2 mid
{
//printf("insert(%d, %d, %d, 左子树[%d,%d]);\n",x1, x2, c, a[i*2].l, a[i*2].r);
insert(x1, x2, c, i*2);

if(oldColor != BLANK && oldColor != MIX)
{
insert(a[i].l, x1, oldColor, i*2);
insert(x2, mid, oldColor, i*2);
insert(mid, a[i].r, oldColor, i*2+1);
}
}
else //x1 mid x2
{
//printf("insert(%d, %d, %d, 左:[%d,%d]右:[%d,%d]);\n",x1, x2, c, a[i*2].l, a[i*2].r, a[i*2+1].l, a[i*2+1].r);
insert(x1, mid, c, i*2);
insert(mid, x2, c, i*2+1);

if(oldColor != BLANK && oldColor != MIX)
{
insert(a[i].l, x1, oldColor, i*2);
insert(x2, a[i].r, oldColor, i*2+1);
}
}
}
}

int cnt[MAXN+2];
int done; //统计的 ”前一段“颜色
void cal(int i) //CALL: cal(1);
{
if(a[i].c == BLANK) { done=BLANK; return; }
else if(a[i].c != MIX) //纯色
{
if(done == BLANK || a[i].c != done) //!③前一段颜色相同的话,不记录,而若前一段无色,可以记录
cnt[a[i].c]++;
done=a[i].c;
}
else if(a[i].r-a[i].l >1) //混合,要遍历子树,加 判断是否叶子
{
cal(i*2);
cal(i*2+1);
}
}
void print()
{
for(int i=0; i<MAXN; i++) //8000种颜色
{
if(cnt[i])
{
printf("%d %d\n", i, cnt[i]);
}
}
}

int n;
int main()
{
init(0, 8000, 1);

while(scanf("%d", &n) != EOF)
{
clear(1);
memset(cnt, 0, sizeof(cnt));

for(int i=0; i<n; i++)
{
int x1, x2, c;
x1=Rint(); x2=Rint(); c=Rint();
insert(x1, x2, c, 1); //从顶端插入
}

done=BLANK; //前一段 无色
cal(1);
print();
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  colors insert c struct bt