BZOJ 2157 旅游 (树链剖分)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2157

这道题给出的是边权,所以我们要把它转换成点权。

题目要求操作:

1.查询景区u,v之间所有桥愉悦值的总和

2.查询景区u,v之间桥愉悦值的最大值

3.查询景区u,v之间桥愉悦值的最小值

4.把景区u,v之间桥的愉悦值全部-1

5.把第i座桥的愉悦值修改为C

思路:因为城市任意两点之间只有一条路径,于是可以把这座城市看成是一颗树,用树链剖分可以进行上面需要的操作。

细节:

1.向下更新时,把左右孩子的lazy标记异或1,而不是直接赋1

2.区间值-1时,把维护的suml取反,maxl,minl交换后取反即可

3.所谓的桥,即是我们用邻接表存储的边,这里我们从下标2开始存储边,因为存储的是无向边,所以我们只需把桥的编号 i << 1, i << 1 | 1得到的即是邻接表edge的下标

(例如第一条桥肯定是edge[2],edge[3]),这样我们就能找到每条桥对应的点了(然后比较一下两条边的dep,这条桥的权值属于深度较大的点),这样我们就成功地把边权转换为了点权

4.景区u,v之间进行操作时,当两个点u,v跳到同一条重链时,深度较小的点的权值不应被考虑,因为操作的是u,v之间的边权,深度较小点的边权肯定不在u,v之间

#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <ctype.h>
#include <map>
#include <vector>
#include <set>
#include <bitset>
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define L(rt) rt << 1
#define R(rt) rt << 1 | 1
#define INF 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
static const int MAX_N = 1e5 + 5;
static const int Mod = 10007;
struct Edge {
    int to, w, next;
}edge[MAX_N << 1];
int head[MAX_N];    //链式前向星
int a[MAX_N];
int siz[MAX_N], son[MAX_N], top[MAX_N], fa[MAX_N], id[MAX_N], dep[MAX_N], rk[MAX_N];
int cnt, tot;
void dfs1(int u, int f, int d) {     //第一次dfs得到重儿子
    siz[u] = 1;
    son[u] = 0;
    fa[u] = f;
    dep[u] = d;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (v == f) continue;    //不走重复路
        a[v] = edge[i].w;
        dfs1(v, u, d + 1);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
    }
}
void dfs2(int u, int t) {     //将重儿子连接成重链,轻儿子连接成轻链(得到区间)
    top[u] = t;
    id[u] = ++cnt;
    rk[cnt] = u;
    if (son[u]) dfs2(son[u], t);  //优先处理重链
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (v != son[u] && v != fa[u]) dfs2(v, v);
    }
}
int getPoint(int u) { return dep[edge[u << 1].to] > dep[edge[u << 1 | 1].to] ? edge[u << 1].to : edge[u << 1 | 1].to; }
struct Node {
    int l, r;
    int minl, maxl, suml, tag;
}T[MAX_N << 2];
void prework() {
    memset(head, 0, sizeof(head));
    cnt = 0;
    tot = 1;
}
void addEdge(int u, int v, int w) {
    edge[++tot].to = v;
    edge[tot].next = head[u];
    edge[tot].w = w;
    head[u] = tot;
}
void pushUp(int rt) {
    T[rt].suml = T[L(rt)].suml + T[R(rt)].suml;
    T[rt].maxl = max(T[L(rt)].maxl, T[R(rt)].maxl);
    T[rt].minl = min(T[L(rt)].minl, T[R(rt)].minl);
}
void build(int rt, int l, int r) {
    T[rt].l = l;
    T[rt].r = r;
    T[rt].tag = 0;
    if (l == r) {
        T[rt].maxl = T[rt].minl = T[rt].suml = a[rk[l]];
        return;
    }
    int mid = l + r >> 1;
    build(lson);
    build(rson);
    pushUp(rt);
}
void pushNow(int rt) {
    swap(T[rt].maxl, T[rt].minl);
    T[rt].maxl = -T[rt].maxl;
    T[rt].minl = -T[rt].minl;
    T[rt].suml = -T[rt].suml;
    T[rt].tag ^= 1;
}
void pushDown(int rt) {
    if (T[rt].tag) {
        pushNow(L(rt));
        pushNow(R(rt));
        T[rt].tag = 0;
    }
}
void updatePoint(int rt, int pos, int c) {
    if (T[rt].l == T[rt].r) {
        T[rt].maxl = T[rt].minl = T[rt].suml = c;
        return;
    }
    pushDown(rt);
    int mid = T[rt].l + T[rt].r >> 1;
    if (pos <= mid) updatePoint(L(rt), pos, c);
    else updatePoint(R(rt), pos, c);
    pushUp(rt);
}
void updateInterval(int rt, int ql, int qr) {
    if (T[rt].l > qr || T[rt].r < ql) return;
    if (T[rt].l >= ql && T[rt].r <= qr) {
        pushNow(rt);
        return;
    }
    pushDown(rt);
    int mid = T[rt].l + T[rt].r >> 1;
    if (ql <= mid) updateInterval(L(rt), ql, qr);
    if (qr > mid) updateInterval(R(rt), ql, qr);
    pushUp(rt);
}
int queryMax(int rt, int ql, int qr) {
    if (T[rt].l > qr || T[rt].r < ql) return -INF;
    if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].maxl;
    pushDown(rt);
    int ans = -INF;
    int mid = T[rt].l + T[rt].r >> 1;
    if (ql <= mid) ans = max(ans, queryMax(L(rt), ql, qr));
    if (qr > mid) ans = max(ans, queryMax(R(rt), ql, qr));
    return ans;
}
int querySum(int rt, int ql, int qr) {
    if (T[rt].l > qr || T[rt].r < ql) return 0;
    if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].suml;
    pushDown(rt);
    int mid = T[rt].l + T[rt].r >> 1;
    int ans = 0;
    if (ql <= mid) ans += querySum(L(rt), ql, qr);
    if (qr > mid) ans +=  querySum(R(rt), ql, qr);
    return ans;
}
int queryMin(int rt, int ql, int qr) {
    if (T[rt].l > qr || T[rt].r < ql) return INF;
    if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].minl;
    pushDown(rt);
    int ans = INF;
    int mid = T[rt].l + T[rt].r >> 1;
    if (ql <= mid) ans = min(ans, queryMin(L(rt), ql, qr));
    if (qr > mid) ans = min(ans, queryMin(R(rt), ql, qr));
    return ans;
}
void updatePathVal(int u, int v) {
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        updateInterval(1, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    updateInterval(1, id[u] + 1, id[v]);
}
int queryPathMax(int u, int v) {
    int ans = -INF;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        ans = max(ans, queryMax(1, id[top[u]], id[u]));
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    ans = max(ans, queryMax(1, id[u] + 1, id[v]));
    return ans;
}
int queryPathSum(int u, int v) {
    int ans = 0;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        ans += querySum(1, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    ans += querySum(1, id[u] + 1, id[v]);
    return ans;
}
int queryPathMin(int u, int v) {
    int ans = INF;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        ans = min(ans, queryMin(1, id[top[u]], id[u]));
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    ans = min(ans, queryMin(1, id[u] + 1, id[v]));
    return ans;
}
void mainwork(){
    /*freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);*/
    int n, q;
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        ++u, ++v;
        addEdge(u, v, w);
        addEdge(v, u, w);
    }
    dfs1(1, 1, 1);
    dfs2(1, 1);
    build(1, 1, n);
    scanf("%d", &q);
    while (q--) {
        char opt[5];
        int u, v, c;
        scanf("%s%d%d", opt, &u, &v);
        if (opt[0] == 'C') updatePoint(1, id[getPoint(u)], v);
        else if (opt[0] == 'N') updatePathVal(u + 1, v + 1);
        else if (opt[1] == 'U') printf("%d\n", queryPathSum(u + 1, v + 1));
        else if (opt[1] == 'I') printf("%d\n", queryPathMin(u + 1, v + 1));
        else  printf("%d\n", queryPathMax(u + 1, v + 1));
    }
}
int main() {
    prework();
    mainwork();
    return 0;
}
View Code

 

posted @ 2019-07-30 15:01  html_11  阅读(126)  评论(0编辑  收藏  举报