题目链接:Jiu Yuan Wants to Eat
题目大意
一颗树,n各节点(
n≤105
n
≤
10
5
)每个节点上有一个值
ai
a
i
(
ai≤264)
a
i
≤
2
64
)
有四种操作
1. 将u到v路径上所有节点值乘以x(
x≤264)
x
≤
2
64
)
2. 将u到v路径上所有节点值加上x(
x≤264)
x
≤
2
64
)
3. 将u到v路径上所有节点的值按位取反
4. 输出u到v路径所有节点值的和
所有操作都是在MOD
264
2
64
下
思路
很明显是树链剖分加线段树, 124操作都很简单,3有点麻烦,但我们可以注意到操作是在MOD
264
2
64
下的
c++中采用补码表示整数,对一个数取相反数(负数)等于对一个数按位取反再加一,所以对一个数按位取反也就相当于对其取相反数(乘以-1)再减一(加上-1),转换成了前两种操作
这样我们只需要树链剖分加线段树就能解决,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;
}