POJ 2777
/* 線段區間染色,並統計區間內顏色個數 因為顏色不多可以用位元運算,但是我還是用數組記錄 注意:C的>>和<<運算子比+ - 低,x << 1 + 1來表示x * 2 + 1是錯的,必須套上括弧 即(x << 1) + 1,已經不止一次犯這個錯誤了。 精簡了一下代碼。但還是上百行…… 2011-07-29 07:59*/#include <stdio.h>#define MAXN 1000000struct node{ int l, r, c;}t[MAXN];int c[32];void build(int l, int r, int x){ t[x].l = l; t[x].r = r; t[x].c = 1; if (l == r) return; int m = (l + r) >> 1; build(l, m, x << 1); build(m + 1, r, (x << 1) + 1);}void update(int l, int r, int c, int x){ if ((l == t[x].l) && (r == t[x].r)) return t[x].c = c; // else if (t[x].l < t[x].r) { int m = (t[x].l + t[x].r) >> 1; if (t[x].c >= 1) { t[x << 1].c = t[(x << 1) + 1].c = t[x].c; t[x].c = -1; } if (r <= m) update(l, r, c, x << 1); else if (l > m) update(l, r, c, (x << 1) + 1); else { update(l, m, c, (x << 1)); update(m + 1, r, c, (x << 1) + 1); } }}void query(int l, int r, int x){ if (t[x].c > 0) return c[t[x].c] = 1;// else if (t[x].c == -1 && t[x].l < t[x].r) { int m = (t[x].l + t[x].r) >> 1; if (r <= m) query(l, r, x << 1); else if (l > m) query(l, r, (x << 1) + 1); else { query(l, m, x << 1); query(m + 1, r, (x << 1) + 1); } }}int count(){ int i, sum = 0; for(i = 1; i <= 30; i++) sum += c[i]; return sum;}void swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp;}int main(){ int n, t, o; while (scanf("%d%d%d", &n, &t, &o) == 3) { build(1, n, 1); while (o--) { char ch[2]; scanf("%s", &ch); if (ch[0] == 'C') { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (a > b) swap(&a, &b); update(a, b, c, 1); } else { int a, b; scanf("%d%d", &a, &b); if (a > b) swap(&a, &b); memset(c, 0, sizeof(c)); query(a, b, 1); printf("%d\n", count()); } } } return 0;}
HDU 1698
/*題意:初始時n個權值為1的技能,給出m條改變區間[x..y]的技能為1,2或3的指令,最後求技能總的權值演算法:成段更新,區間求和,線段樹維護。體會:有時候C語言也要用G++交才能過。Debug好久,主要是因為改變技能時按照原來寫的線段樹的套路寫的,對於不同的要求要靈活運用,不能生搬硬套*/#include <stdio.h>#define MAXN 400000#define ROOT 1struct{ int left,right,cover;}t[MAXN];//cover域表示所控制區間內的技能,若為-1則為多種void build(int p, int left, int right){ t[p].left = left; t[p].right = right; t[p].cover = 1; if (left == right) return; int m = (left + right) / 2; build(p*2, left, m); build(p*2+1, m+1, right);}//建樹,初始時都是為1的技能void change(int p, int left , int right, int color){ if ((t[p].left >= left) && (t[p].right <= right)) { t[p].cover = color; return; }//如果樹控制的區間都要染色那麼改一下cover域就行了 if (t[p].cover != -1) { t[p*2].cover = t[p*2+1].cover = t[p].cover; t[p].cover = -1; }//否則如果樹控制區間的顏色是同一種,則可能變成多種,cover改為-1,而且在上一種情況中左右子樹沒有更新,現在要用了就要更新一下 int m = (t[p].left + t[p].right) / 2; if (left <= m) change(p*2, left, right, color); if (right > m ) change(p*2+1, left, right, color); //錯就錯在這步,只要涉及左子樹就更新左子樹,涉及右子樹就更新右子樹,原來寫成如果在左子樹範圍內更新左子樹,在右子樹範圍內就更新右子樹了。模仿在網上看的程式,以為可以少些點的,但是寫錯了,偷懶失敗。}int count(int p, int left, int right){ int m = (t[p].left + t[p].right) / 2; if (t[p].left == left && t[p].right == right) { if (t[p].cover != -1) return t[p].cover * (t[p].right - t[p].left + 1); else return count(p*2, left, m) + count(p*2+1, m+1, right); }//統計,如果在該樹單調則統計否則分別統計左右子樹 if (m >= right) return count(p*2, left, m); else if (m < left) return count(p*2+1, m+1, right); else return count(p*2, left, m) + count(p*2+1, m+1, right); //不包括整棵樹的話就分別統計了}//其實我覺得這道題是統計整棵樹,那麼count過程似乎可以更簡單,但沒仔細想int main(){ int i,j,k,m,n,t,x,y,z; scanf("%d", &t); for (k = 1; k <= t; k++) { scanf("%d%d", &n, &m); build(ROOT, 1, n); for (i = 1; i <= m; i++) { scanf("%d%d%d", &x, &y, &z); change(ROOT, x, y, z); } printf("Case %d: The total value of the hook is %d.\n",k,count(1,1,n)); }//注意輸出有個. return 0;}