標籤:http 使用 io for ar 代碼 時間 amp
題:敵兵布陣
標準線段樹模板代碼:
#include<cstdio>#include<cstring>const int maxn = 500000 + 10;struct Node{ int left, right, count;}node[maxn];int a[maxn];/**************************************************建樹****************************i是區間序號**************l是區間i左邊界,r是區間i右邊界***從1到n開始建樹,直到區間長度為1***即l=r時,結束。count記錄區間和**************************************/void maketree(int l, int r, int i){ node[i].left = l; node[i].right = r; if(l == r){ node[i].count = a[l]; return ; } int m = (l + r)/2; maketree(l, m, 2*i); maketree(m + 1, r, 2*i + 1); node[i].count = node[2*i].count + node[2*i + 1].count;}/*********************************************************更新********************i區間序號,x要更新的點。y要更新的值**********flag判斷更新方式*****************************************************/void updatetree(int i, int x, int y, int flag){ int l = node[i].left; int r = node[i].right; int m = (l + r)/2; if(r == l){ if(flag) node[i].count += y; else node[i].count -= y; return; } if(x <= m) updatetree(2*i, x, y, flag); else updatetree(2*i + 1, x, y, flag); if(flag) node[i].count += y; else node[i].count -= y; return;}/**************************************************查詢****************************************************/int querytree(int l, int r, int i){ int m = (node[i].left + node[i].right)/2; if(node[i].right <= r && node[i].left >= l) return node[i].count; int ans = 0; if(r <= m) return querytree(l, r, 2*i); else if(l > m) return querytree(l, r, 2*i + 1); else return querytree(l, m, 2*i) + querytree(m + 1, r, 2*i + 1);}int main(){ int T, n; char str[20]; scanf("%d", &T); for(int i = 1; i <= T; i++){ printf("Case %d:\n", i); scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); maketree(1, n, 1); int x, y; while(scanf("%s", str)){ if(str[0] == 'E') break; scanf("%d%d", &x, &y); if(str[0] == 'Q') printf("%d\n", querytree(x, y, 1)); else if(str[0] == 'A') updatetree(1, x, y, true); else updatetree(1, x, y, false); } } return 0;}
優美的線段樹代碼:
#include <cstdio>/*****************************靈活的使用宏定義******************************/#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1const int maxn = 55555;int sum[maxn<<2];void PushUP(int rt) {sum[rt] = sum[rt<<1] + sum[rt<<1|1];}/***************************************************建樹*************** 此處並沒有使用結構體,只是記錄了區間和sum,但l,r與區間序號緊密關聯***********************************/void build(int l,int r,int rt) {if (l == r) {scanf("%d",&sum[rt]);return ;}int m = (l + r) >> 1;build(lson);build(rson);PushUP(rt);}/*************************************** *****************更新***************** 此處沒用標記更新方式(加或減),巧妙 地在調用時處理了加號或減號,減少函數參數***************************************/void update(int p,int add,int l,int r,int rt) {if (l == r) {sum[rt] += add;return ;}int m = (l + r) >> 1;if (p <= m) update(p , add , lson);else update(p , add , rson);PushUP(rt);}/*********************************************************查詢****************** 巧妙地引用了變數ret,減少了對m的討論***************************************/int query(int L,int R,int l,int r,int rt) {if (L <= l && r <= R) {return sum[rt];}int m = (l + r) >> 1;int ret = 0;if (L <= m) ret += query(L , R , lson);if (R > m) ret += query(L , R , rson);return ret;}int main() {int T , n;scanf("%d",&T);for (int cas = 1 ; cas <= T ; cas ++) {printf("Case %d:\n",cas);scanf("%d",&n);build(1 , n , 1);char op[10];while (scanf("%s",op)) {if (op[0] == 'E') break;int a , b;scanf("%d%d",&a,&b);if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));else if (op[0] == 'S') update(a , -b , 1 , n , 1);else update(a , b , 1 , n , 1);}}return 0;}
上述兩種代碼思路相同,只是代碼風格不同,已耗用時間,佔用記憶體還是相同的。此題只涉及單點更新和區間求和,所以可以用樹狀數組求解,代碼更簡潔,運行速度更快。但樹狀數組可以求區間和,無法求出區間最值,通用解法仍是用線段樹求解。
樹狀數組的代碼:
#include<cstdio>#include<cstring>using namespace std;const int maxn = 50000 + 10;int len, a[maxn];char str[50];int lowbit(int x){ return x&(-x);}/******************************更新********************************/void update(int i, int v){ while(i <= len){ a[i] += v; i += lowbit(i); }}/*****************************求和******************************/int sum(int i){ int sum = 0; while(i > 0){ sum += a[i]; i -= lowbit(i); } return sum;}int main(){ int T, v; scanf("%d", &T); for(int i = 1; i <= T; i++){ memset(a, 0, sizeof(a)); scanf("%d", &len); for(int j = 1; j <= len; j++){ scanf("%d", &v); update(j, v); } printf("Case %d:\n", i); while(scanf("%s", str)){ if(str[0] == 'E') break; int x, y; scanf("%d%d", &x, &y); if(str[0] == 'A') update(x, y); else if(str[0] == 'S') update(x, -y); else printf("%d\n", sum(y)-sum(x-1)); } } return 0;}