看完線段樹本來打算找這道基礎題練手,但是悲慘的砸進去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 -2struct 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=indexa[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=-2if(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;}elseif(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");}}