Just a Hook (線段樹,區間更新)
阿新 • • 發佈:2019-01-10
hook有三種stick,分別為1號,2號, 3號,長度分別為1,2,3;T個測試樣例, N個stick,Q個操作,每次操作改變x-y區間內stick的值,最後求和;
話不多說,程式碼奉上:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #define MAX 100000+5 using namespace std; int arr[MAX]; //儲存初始值(對樹初始化時存入葉子的值); struct node{ //結構體儲存樹的結點; int left; //該結點的左邊界; int right; //右邊界; int val; //結點的值;此題中是區間和; int mark; //標記; }tr[MAX<<2]; void pushup(int node) //維護結點; { tr[node].val=tr[node<<1].val+tr[node<<1|1].val; return; } void build(int node, int left, int right) //建線段樹,傳參:樹根, 左邊界,右邊界; { tr[node].left=left; //確定該結點的作用區間; tr[node].right=right; //同上; tr[node].mark=0; //把標記初始化為零(此句必須有
); if(tr[node].left==tr[node].right) //該結點為葉結點,初始化葉結點; { tr[node].val=arr[left]; return; } int mid=(left+right)>>1; build(node<<1, left, mid); build(node<<1|1, mid+1, right); pushup(node); } void mark(int node) //判斷是否標記; { if(tr[node].mark){ tr[node].val=tr[node].mark*(tr[node].right-tr[node].left+1); if(tr[node].left!=tr[node].right){ //if是葉子則沒有下一層可標記,不是葉子就標記下一層; tr[node<<1].mark=tr[node].mark; tr[node<<1|1].mark=tr[node].mark; } tr[node].mark=0; //消除標記; } return; } void update(int node, int left, int right, int x)//區間更新; { mark(node); //每次更新前先看該層是否有標記,有標記就把標記跑一遍; if(left>tr[node].right || right<tr[node].left) return; if(left<=tr[node].left && right>=tr[node].right){ tr[node].val=x*(tr[node].right-tr[node].left+1); tr[node].mark=x; //標記結點; return; } update(node<<1, left, right, x); update(node<<1|1, left, right, x); pushup(node); //維護父結點; } int main(){ int T, cnt=0; scanf("%d",&T); while(T--){ cnt++; int N, i; scanf("%d",&N); for(i=1; i<=N; i++) arr[i]=1; build(1, 1, N); int Q; scanf("%d",&Q); while(Q--){ int a, b, c; scanf("%d%d%d",&a,&b,&c); update(1, a, b, c); } printf("Case %d: The total value of the hook is %d.\n",cnt,tr[1].val); } return 0; }