HDU 5997 & bestcoder #90 C 线段树

传送门 : HDU 5997

题解

最初想过用vector存储, 但是没敢写….
区间合并 + 成段更新
这题和普通线段树区间更新的区别就是待更新的区间不确定, 所以只要把要更新区间表示出来, 就行了
x -> y找到x代表的vector存储的多个成段区间, 一个个更新,
这些段加到y的段里, 然后清楚x的段
今天水过结果920MS,目前垫底。。。。打不动


AC Code

#include
#include
#include
#include
#include
using namespace std;
#define mid ((l + r) >> 1)
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r

typedef long long LL;

const int maxn = 1000000 + 5;
int n, q;

struct Node{
    int lv, rv, ans, la;
}node[maxn << 2];

int co[maxn];

struct Seg{//段
    int l, r;
};

vector s[maxn];

void pushUp(Node &res, Node p, Node q) {//合并
    res.lv = p.lv;
    res.rv = q.rv;
    res.ans = p.ans + q.ans;
    if (p.rv == q.lv) --res.ans;
}

void build(int rt, int l, int r) {
    node[rt].la = 0;
    if (l == r) {
        //scanf("%d", &node[rt].lv);
        node[rt].ans = 1;
        node[rt].rv = node[rt].lv = co[l];
        return;
    }

    build(ls);
    build(rs);
    pushUp(node[rt], node[rt << 1], node[rt << 1 | 1]);
}

void down(int f, int s) {
    node[s].la = node[f].la;
    node[s].lv = node[f].lv;
    node[s].rv = node[f].rv;
    node[s].ans = 1;
}

void pushDown(int rt) {
    if (node[rt].la) {
        down(rt, rt << 1);
        down(rt, rt << 1 | 1);
        node[rt].la = 0;
    }
}
void update(int rt, int l, int r, int L, int R, int b) {
    //printf("%d %d %d %d\n", l, r, L, R);
    if (L <= l && R >= r) {
        node[rt].lv = node[rt].rv = b;
        node[rt].la = b;
        return;
    }

    pushDown(rt);
    if(L <= mid)    update(ls, L, R, b);
    if(R > mid )    update(rs, L, R, b);
    pushUp(node[rt], node[rt << 1], node[rt << 1 | 1]);
}

Node query(int rt, int l, int r, int L, int R) {

    if (L == l && R == r) {
        return node[rt];
    }
    //pushDown(rt);
    Node p, q, res;
    if (L > mid) {
        return query(rs, L, R);
    }
    if (R <= mid) {
        return query(ls, L, R);
    }

    p = query(ls, L, mid);
    q = query(rs, mid + 1, R);
    pushUp(res, p, q);

    return res;
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    cin.sync_with_stdio(false);
    int T, op, a, b;
    scanf("%d", &T);

    while (T--) {
        scanf("%d%d", &n, &q);
        for (int i = 0; i < 1000000; ++i) s[i].clear();
        int tmp = -1;
        Seg tt;
        for (int i = 1; i <= n; ++i) {//预处理
            scanf("%d", &co[i]);
            if (tmp == -1) {
                tt.l = i;
                tmp = co[i];
            }
            if (tmp != co[i]) {
                tt.r = i - 1;
                s[tmp].push_back(tt);
                tt.l = i;
                tmp = co[i];
            }
        }
        tt.r = n;
        s[tmp].push_back(tt);
        build(1, 1, n);
        while (q--) {
            scanf("%d%d%d", &op, &a, &b);
            if (op == 1) {
                if (a == b) continue;
                for (int i = 0; i < s[a].size(); ++i) {//update
                    update(1, 1, n, s[a][i].l, s[a][i].r, b);
                    s[b].push_back(s[a][i]);
                }
                s[a].clear();
            }
            else {

                Node tmp = query(1, 1, n, a, b);
                printf("%d\n", tmp.ans);
            }
        }
    }


    return 0;
}

你可能感兴趣的:(tree),HDU,线段树区间合并)