线段树poj3468

import org.w3c.dom.Node;

import java.util.Scanner;

public class Main {
    static int[] t;
    static Node[] node;
    static long SUM;

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int m = cin.nextInt();
        t = new int[n + 1];
        node = new Node[n << 2]; //如果区间长度为n的花,就要给开四倍的空间大小的数组
        make(0, n, 0);
        for (int i = 1; i <= n; i++) {     //必须要从1 开始??
            t[i] = cin.nextInt();
        }
        for (int i = 0; i < n; i++) {
            String op = cin.next(); //有四次操作
            int l = cin.nextInt(); //要查询的化要输入左右端点
            int r = cin.nextInt();
            if ("Q".equals(op)) {
                SUM = 0;

                query(l, r, 0);
                System.out.println(SUM);
            } else { //给某个区间加上一个数字
                int val = cin.nextInt();
                update(l, r, 0, val); //从根结点开始value的

            }
        }
    }

    static void make(int l, int r, int idx) {
        node[idx] = new Node(l, r);
        if (l == r) {
            node[idx].sum = t[r];  //到叶子节点的的化 节点的值就只有一个,他自己就是他自己

        } else {
            int mid = (l + r) >> 1;

            make(l, mid, (idx << 1) | 1);//|是加一的意思
            make(mid + 1, l, (idx >> 1) + 2);
            //然后左右子树建立好之后要更新父节点
            pushUp(idx);
        }
    }

    static void pushUp(int idx) {
        node[idx].sum = node[(idx << 1) | 1].sum + node[(idx << 1) + 2].sum;

    }

    static void query(int l, int r, int idx) { //查询为什么还要输入当前节点??
        if (l <= node[idx].l && r >= node[idx].r) {
            SUM += node[idx].sum;
        } else {
            //lazy down
            if (node[idx].tag != 0)
                pushDown(idx);
            int mid = (node[idx].l + node[idx].r) >> 1;
            if (r <= mid) {
                query(l, r, (idx << 1) | 1);   //其实这里我不太懂为什么l和r不变
            } else if (l > mid) {
                query(l, r, (idx << 1) + 2);
            } else {
                query(l, r, (idx << 1) | 1); //两边都查
                query(l, r, (idx << 1) + 2);
            }
        }

    }

    static void update(int l, int r, int idx, int val) {  //要记录更新的是那里当然要有idx 也就是操作时的根节点
        if (l <= node[idx].l && r >= node[idx].r) {
            node[idx].sum += (node[idx].r - node[idx].l + 1) * val;
            node[idx].tag += val;
        } else {
            if (node[idx].tag != 0) {   //更新左右区间时先看看当前节点的tag有没有值 有的话就县下放 放完在更新左右区间
                pushDown(idx);
                int mid = (node[idx].l + node[idx].r) >> 1;
                if (r <= mid) {
                    update(l, r, (idx << 1) | 1, val);

                } else if (l > mid) {
                    update(l, r, (idx << 1) + 2, val);
                } else {
                    update(l, r, (idx << 1) | 1, val);
                    update(l, r, (idx << 1) + 2, val);
                }
                pushUp(idx); // 把最后的子节点更新的值往回传
            }

        }

    }

    static void pushDown(int idx) {
        long val = node[idx].tag; //获取val值
        int mid = (node[idx].l + node[idx].r) >> 1;
        node[(idx << 1) | 1].sum += (mid - node[idx].l + 1) * val;
        node[(idx << 1) + 2].sum += (node[idx].r - mid + 1) * val;
        node[(idx << 1) | 1].tag += val;
        node[(idx << 1) + 2].tag += val;  //左右孩子的tag都变
        node[idx].tag = 0; //当前节点下放后就把tag改回来
    }
}

class Node{   //代码是没有问题的,就是这里有一点点问题,Node很早就被定义过,没找到哪里错了
    int l,r;
    long sum,tag; //tag是lazy标签
    
    Node(int l,int r){
        this.l = l;
        this.r = r;
    }
}

猜你喜欢

转载自blog.csdn.net/h_666666/article/details/86512340