1. 程式人生 > >ACM-ICPC 2018 焦作賽區網路預賽 E. Jiu Yuan Wants to Eat 樹鏈剖分 線段樹

ACM-ICPC 2018 焦作賽區網路預賽 E. Jiu Yuan Wants to Eat 樹鏈剖分 線段樹

題目大意

一顆樹,n各節點(n105)每個節點上有一個值ai(ai264) 有四種操作 1. 將u到v路徑上所有節點值乘以x(x264) 2. 將u到v路徑上所有節點值加上x(x264) 3. 將u到v路徑上所有節點的值按位取反 4. 輸出u到v路徑所有節點值的和 所有操作都是在MOD264

思路

很明顯是樹鏈剖分加線段樹, 124操作都很簡單,3有點麻煩,但我們可以注意到操作是在MOD264下的 c++中採用補碼錶示整數,對一個數取相反數(負數)等於對一個數按位取反加一,所以對一個數按位取反也就相當於對其取相反數

減一 這樣我們只需要樹鏈剖分加線段樹就能解決,MOD直接利用ull的自然溢位就好了 線段樹更新函式void update(int L, int R, ull mm, ull a, int l, int r, int rt) :將區間[L, R]乘以mm再加上a 這樣操作1:update(L, R, x, 0, 1, n, 1) 操作2:update(L, R, 1, x, 1, n, 1) 操作3:update(L, R, -1, -1, 1, n, 1) 設兩個lazy標記mul和inc表示乘法和加法操作

程式碼

正確通過 2018-09-15 17:49 1900ms 22000kB c++

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
const int maxn = 1e5 + 100;

int n, m;

struct edge
{
    int to, nxt;
    edge(int t = 0, int n = 0): to(t), nxt(n) {}
};
edge es[maxn * 2];
int head[maxn];
int siz[maxn], son[maxn], dep[maxn], faz[maxn];
int top[maxn], id[maxn], rid[maxn], dfs_clocks;
inline
void addedge(int i, int u, int v) { es[i * 2] = edge(v, head[u]); head[u] = i * 2; es[i * 2 + 1] = edge(u, head[v]); head[v] = i * 2 + 1; } void dfs1(int u, int fa, int depth) { dep[u] = depth; faz[u] = fa; siz[u] = 1; for (int i = head[u]; i; i = es[i].nxt) { int v = es[i].to; if (v == fa) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (son[u] == 0 || siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int tp) { top[u] = tp; id[u] = dfs_clocks; rid[dfs_clocks++] = u; if (son[u]) dfs2(son[u], tp); for (int i = head[u]; i; i = es[i].nxt) { int v = es[i].to; if (v != son[u] && v != faz[u]) dfs2(v, v); } } #define ls l, m, rt<<1 #define rs m+1, r, rt<<1|1 ull sum[maxn << 2], mul[maxn << 2], inc[maxn << 2]; void pushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void pushDown(int rt, int m) { if (mul[rt] != 1) { mul[rt << 1] *= mul[rt]; inc[rt << 1] *= mul[rt]; mul[rt << 1 | 1] *= mul[rt]; inc[rt << 1 | 1] *= mul[rt]; sum[rt << 1] *= mul[rt]; sum[rt << 1 | 1] *= mul[rt]; mul[rt] = 1; } if (inc[rt]) { inc[rt << 1] += inc[rt]; inc[rt << 1 | 1] += inc[rt]; sum[rt << 1] += (m - m / 2) * inc[rt]; sum[rt << 1 | 1] += (m / 2) * inc[rt]; inc[rt] = 0; } } void build(int l, int r, int rt) { mul[rt] = 1; inc[rt] = 0; sum[rt] = 0; if (l == r) return ; int m = (l + r) / 2; build(ls); build(rs); pushUp(rt); } void update(int L, int R, ull mm, ull a, int l, int r, int rt) { if (L <= l && r <= R) { mul[rt] *= mm; inc[rt] *= mm; inc[rt] += a; sum[rt] *= mm; // sum[rt] += a; sum[rt] += a*(r-l+1); return ; } pushDown(rt, r - l + 1); int m = (l + r) / 2; if (L <= m) update(L, R, mm, a, ls); if (R > m) update(L, R, mm, a, rs); pushUp(rt); } ull query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; } pushDown(rt, r - l + 1); int m = (l + r) / 2; ull ret = 0; if (L <= m) ret += query(L, R, ls); if (m < R) ret += query(L, R, rs); return ret; } void update_path(int x, int y, ull m, ull a) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); // update_range(id[top[x]], id[x], z); update(id[top[x]], id[x], m, a, 1, n, 1); x = faz[top[x]]; } if (dep[x] > dep[y]) swap(x, y); update(id[x], id[y], m, a, 1, n, 1); } ull query_path(int x, int y) { ull ret = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); // ret = max(ret, query(id[top[x]], id[x], 1, n, 1)); ret += query(id[top[x]], id[x], 1, n, 1); x = faz[top[x]];//error: x = faz[x]; } if (dep[x] > dep[y]) swap(x, y); ret += query(id[x], id[y], 1, n, 1); return ret; } int main() { while (scanf("%d", &n) == 1) { memset(head, 0, sizeof(head)); memset(son, 0, sizeof(son)); dfs_clocks = 1; int b; for (int i = 2; i <= n; ++i) { scanf("%d", &b); addedge(i, b, i); } dfs1(1, 1, 1); dfs2(1, 1); build(1, n, 1); scanf("%d", &m); for (int i = 0; i < m; ++i) { int op; int u, v; ull x; scanf("%d", &op); if (op == 1) { scanf("%d%d%llu", &u, &v, &x); update_path(u, v, x, 0); } else if (op == 2) { scanf("%d%d%llu", &u, &v, &x); update_path(u, v, 1, x); } else if (op == 3) { scanf("%d%d", &u, &v); update_path(u, v, -1, -1); } else { scanf("%d%d", &u, &v); printf("%llu\n", query_path(u, v)); } } } return 0; }