1. 程式人生 > >Just a Hook (線段樹,區間更新)

Just a Hook (線段樹,區間更新)

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; }