2011-10-12 20:36

HDU 1698 遗传线段树

题意:初始一序列为1,各种操作后序列总和多少?

分析:各种操作->线段树,本以为很水,用之前自己写的线段树,各种超时+郁闷,后来找到自己第一次接触线段树的那道题,标程里面用到了线段树遗传效应,省了不少时间;

代码:

#include <cstdio>
#include <cstring>

const int M = 100005;

int vv;

struct node {
    int a, b, m, r; //用r 做遗传
}tree[4*M];

void build(int x, int y, int k) {
    tree[k].a = x;
    tree[k].b = y;
    tree[k].r = 0;
    if (y > x) {
        int mid = (x+y) >> 1;
        build(x, mid, k<<1);
        build(mid+1, y, k<<1|1);
        tree[k].m = tree[k<<1].m + tree[k<<1|1].m;
    }
    else if (x == y) {
        tree[k].m = 1;
    }
}
void operate(int x, int y, int k) {
    int mid = (tree[k].a+tree[k].b)>>1;
    if (x==tree[k].a && tree[k].b==y) { //不需要更新到每个结点
        tree[k].m = vv * (y - x +1);
        tree[k].r = vv; //用r 先记录此次操作
        return;
    }
    if (tree[k].r!=0) { //如果要对k 的孩子进行操作,则将先前k 的属性r 遗传给左右孩子
        tree[k<<1].m = tree[k].r * (tree[k<<1].b-tree[k<<1].a+1);
        tree[k<<1|1].m = tree[k].r * (tree[k<<1|1].b-tree[k<<1|1].a+1);
        tree[k<<1].r = tree[k<<1|1].r = tree[k].r;
        tree[k].r = 0; //遗传后清零
    }
    if (x > mid) {
        operate(x, y, k<<1|1);
    }
    else if (y <= mid) {
        operate(x, y, k<<1);
    }
    else {
        operate(x, mid, k<<1);
        operate(mid+1, y, k<<1|1);
    }
    tree[k].m = tree[k<<1].m + tree[k<<1|1].m;
}

int main() {
    int tc, cc = 1;
    int n, q;
    scanf("%d", &tc);
    while (tc--) {
        scanf("%d", &n);
        build(1, n, 1);
        scanf("%d", &q);
        while (q--) {
            int x, y;
            scanf("%d%d%d", &x, &y, &vv);
            operate(x, y, 1);
        }

        printf("Case %d: The total value of the hook is %d.\n", cc++, tree[1].m); 
    }
    return 0;
}

 

 

评论