標籤:
Code[VS]1690 開關燈 題解 時間限制: 1 s 空間限制: 128000 KB 題目等級 : 鑽石 Diamond 題目描述 Description: YYX家門前的街上有N(2<=N<=100000)盞路燈,在晚上六點之前,這些路燈全是關著的,六點之後,會有M(2<=m<=100000)個人陸續按下開關,這些開關可以改變從第i盞燈到第j盞燈的狀態,現在YYX想知道,從第x盞燈到第y盞燈中有多少是亮著的(1<=i,j,x,y<=N) 輸入描述 Input Description:第 1 行: 用空格隔開的兩個整數N和M第 2..M+1 行: 每行表示一個操作, 有三個用空格分開的整數: 指令號(0代表按下開關,1代表詢問狀態), x 和 y 輸出描述 Output Description:第 1..詢問總次數 行:對於每一次詢問,輸出詢問的結果 範例輸入 Sample Input:4 50 1 20 2 41 2 30 2 41 1 4 範例輸出 Sample Output:12 資料範圍及提示 Data Size & Hint:一共4盞燈,5個操作,下面是每次操作的狀態(X代表關上的,O代表開著的): XXXX -> OOXX -> OXOO -> 詢問1~3 -> OOXX -> 詢問1~4 —————————————————————————————————————————————— 分析:本題最暴力的思路,是用數組類比區間開關燈的操作,但是資料量較大,暴力思路會逾時。這時考慮使用帶延遲標記的線段樹。這道題屬於比較明顯的線段樹題。以下代碼:(代碼比較長^_^)
1 #include "bits/stdc++.h" 2 3 #define maxN 100010 4 5 using namespace std; 6 typedef long long QAQ; 7 8 struct Tree 9 { 10 int l, r ; 11 QAQ sum ;//當前開著的燈數量 12 bool idv;//開關燈的延遲標記 13 }; 14 15 QAQ Min(QAQ a, QAQ b) 16 { 17 return a > b ? b : a; 18 } 19 20 Tree tr[maxN << 2]; 21 22 void Push_down ( int i , int m) 23 { 24 if(tr[i].idv)//當前結點有延遲標記 25 { 26 tr[i << 1].idv = !tr[i << 1].idv ;//左 27 tr[i << 1 | 1].idv = !tr[i << 1 | 1].idv ;//右 28 tr[i << 1].sum = tr[i << 1].r - tr[i << 1].l + 1 - tr[i << 1].sum ;//所以燈開關狀態取反 29 tr[i << 1 | 1].sum = tr[i << 1 | 1].r - tr[i << 1 | 1].l + 1 - tr[i << 1 | 1].sum ;//同上 30 tr[i].idv = !tr[i].idv ;//清零!!! 31 } 32 } 33 34 void Build_Tree (int x , int y, int i) 35 { 36 tr[i].l = x ;//左端點 37 tr[i].r = y ;//右端點 38 if( x == y)return ; 39 else 40 { 41 QAQ mid = (tr[i].l + tr[i].r ) >> 1 ; 42 Build_Tree ( x , mid , i << 1);//左遞迴 43 Build_Tree (mid + 1 , y , i << 1 | 1);//右遞迴 44 } 45 } 46 47 void Update_Tree (int q , int w , int i) 48 { 49 if( w >= tr[i].r && q <= tr[i].l)//被完全包含 50 { 51 tr[i].idv = !tr[i].idv;//延遲標記 52 QAQ tot = tr[i].r - tr[i].l + 1;//當前結點總共的燈 53 tr[i].sum = tot - tr[i].sum;//開關狀態全部取反 54 return ; 55 } 56 else 57 { 58 Push_down( i , tr[i].r - tr[i].l + 1 );//資訊下傳函數 59 QAQ mid = (tr[i].l + tr[i].r) >> 1; 60 if( q > mid ) 61 { 62 Update_Tree ( q , w , i << 1 | 1); 63 } 64 else if ( w <= mid ) 65 { 66 Update_Tree ( q , w , i << 1); 67 } 68 else 69 { 70 Update_Tree ( q , w , i << 1 | 1); 71 Update_Tree ( q , w , i << 1); 72 } 73 tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum ;//回溯更新 74 } 75 } 76 77 QAQ Query_Tree (int q , int w , int i ) 78 { 79 if( w >= tr[i].r && q <= tr[i].l) 80 { 81 return tr[i].sum;//被完全包含直接傳回值 82 } 83 else 84 { 85 Push_down( i , tr[i].r - tr[i].l + 1 ); 86 QAQ mid = (tr[i].l + tr[i].r ) >> 1; 87 if( q > mid ) 88 { 89 return Query_Tree ( q , w , i << 1 | 1); 90 } 91 else if ( w <= mid ) 92 { 93 return Query_Tree ( q , w , i << 1); 94 } 95 else 96 { 97 return Query_Tree ( q , w , i << 1 | 1) + Query_Tree ( q , w , i << 1); 98 } 99 }100 }101 102 int main ( )103 {104 QAQ N, M;105 int op, l, r;106 scanf("%d%d", &N, &M);107 Build_Tree ( 1 , N , 1 );//建樹操作108 while (M--)109 {110 scanf("%d", &op);111 if( !op )112 {113 scanf("%d%d", &l, &r);114 Update_Tree ( l , r , 1 );//更新樹115 }116 else117 {118 scanf("%d%d", &l, &r);119 printf("%lld\n", Query_Tree ( l , r , 1 ));//查詢120 }121 }122 return 0 ;123 }
( 完 )
Code[VS]1690 開關燈 題解