ACM-ICPC 2018 焦作賽區網路預賽 E. Jiu Yuan Wants to Eat 樹鏈剖分 線段樹
阿新 • • 發佈:2018-12-10
題目大意
一顆樹,n各節點()每個節點上有一個值( 有四種操作 1. 將u到v路徑上所有節點值乘以x( 2. 將u到v路徑上所有節點值加上x( 3. 將u到v路徑上所有節點的值按位取反 4. 輸出u到v路徑所有節點值的和 所有操作都是在MOD下
思路
很明顯是樹鏈剖分加線段樹, 124操作都很簡單,3有點麻煩,但我們可以注意到操作是在MOD下的 c++中採用補碼錶示整數,對一個數取相反數(負數)等於對一個數按位取反再加一,所以對一個數按位取反也就相當於對其取相反數
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;
}