题目链接:https://nanti.jisuanke.com/t/31714
题目大意:给出一棵n个节点的树,每个节点都有权值。接下来进行m次操作,每次操作有以下四种可能:
1 u v x : 将节点u到节点v这条链的路径上的点得权值都乘上x
2 u v x:将节点u到节点v这条链的路径上的点得权值都加上x
3 u v :将节点u到节点v这条链的路径上的点得权值都进行二进制取反
4 u v : 查询节点u到节点v这条链上所有节点的权值和(模上2^64)。
题目思路:由于是要对于树上的链进行修改和查询操作,所以我们很容易就能想到用树链剖分和线段树来维护答案。对于操作1和操作2我们可以用线段树直接维护,对于操作3我们需要进行一些转化。由于树上点的权值都是会模上2^64,所以树上点的权值x取反后的值就等于(2^64-1)-x,这样我们就可以把取反操作分解成为乘法操作和加法操作,即对于x来说,进行取反操作之后就变成了(-1)*x+(-1)(因为-1对于2^64取模之后就变成(2^64-1),所以就可以直接乘上-1)。接下来就考虑在维护线段树的时候更新的先后顺序,由于乘法的更新操作会影响到加法的更新,所以在更新乘法的时候要同时维护加法操作的更新。接下来处理好细节即可。
具体实现看代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
const int inf = 0x3f3f3f3f;
const int MX = 1e5 + 7;
int n, m;
int dep[MX], fa[MX], sz[MX], son[MX], top[MX], id[MX], tot;
vector<int>E[MX];
ull sum[MX << 2], add[MX << 2], mul[MX << 2];
void push_up(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void push_down(int l, int r, int rt) {
int m = (l + r) >> 1;
if (mul[rt] != 1) {
mul[rt << 1] *= mul[rt];
mul[rt << 1 | 1] *= mul[rt];
add[rt << 1] *= mul[rt], add[rt << 1 | 1] *= mul[rt];
sum[rt << 1] *= mul[rt];
sum[rt << 1 | 1] *= mul[rt];
mul[rt] = 1;
}
if (add[rt]) {
add[rt << 1] += add[rt]; add[rt << 1 | 1] += add[rt];
sum[rt << 1] += (ull)(m - l + 1) * add[rt];
sum[rt << 1 | 1] += (ull)(r - m) * add[rt];
add[rt] = 0;
}
}
void build(int l, int r, int rt) {
sum[rt] = add[rt] = 0;
mul[rt] = 1;
if (l == r) return;
int m = (l + r) >> 1;
build(lson); build(rson);
push_up(rt);
}
void update(int op, int L, int R, ull d, int l, int r, int rt) {
if (L <= l && r <= R) {
if (l != r) push_down(l, r, rt);
if (op == 1) {
mul[rt] *= d;
add[rt] *= d;
sum[rt] *= d;
} else if (op == 2) {
add[rt] += d;
sum[rt] += (ull)(r - l + 1) * d;
} else {
mul[rt] *= d;
add[rt] = add[rt] * d + d;
sum[rt] = (ull)(r - l + 1) * d - sum[rt];
}
return;
}
push_down(l, r, rt);
int m = (l + r) >> 1;
if (L <= m) update(op, L, R, d, lson);
if (R > m) update(op, L, R, d, rson);
push_up(rt);
}
ull query_sum(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return sum[rt];
push_down(l, r, rt);
int m = (l + r) >> 1;
ull res = 0;
if (L <= m) res += query_sum(L, R, lson);
if (R > m) res += query_sum(L, R, rson);
push_up(rt);
return res;
}
void dfs1(int u) {
sz[u] = 1; son[u] = 0;
for (int i = 0; i < (int)E[u].size(); i++) {
int v = E[u][i];
if (v == fa[u]) continue;
fa[v] = u; dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
id[u] = ++tot; top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (int i = 0; i < (int)E[u].size(); i++) {
int v = E[u][i];
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
void pre_solve() {
tot = 0;
dfs1(1); dfs2(1, 1);
}
void Update(int op, int u, int v, ull d) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
update(op, id[top[u]], id[u], d, 1, n, 1);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
update(op, id[u], id[v], d, 1, n, 1);
}
ull solve(int u, int v) {
ull ans = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ans += query_sum(id[top[u]], id[u], 1, n, 1);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v);
ans += query_sum(id[u], id[v], 1, n, 1);
return ans;
}
int main() {
// FIN;
while (~scanf("%d", &n)) {
for (int i = 0; i <= n; i++) E[i].clear();
for (int i = 2; i <= n; i++) {
int u; scanf("%d", &u);
E[u].pb(i); E[i].pb(u);
}
pre_solve();
build(1, n, 1);
scanf("%d", &m);
int op, u, v;
ull x;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &op, &u, &v);
if (op == 4) {
ull ans = solve(u, v);
printf("%llu\n", ans);
} else {
if (op < 3)
scanf("%llu", &x);
else x = -1;
Update(op, u, v, x);
}
}
}
return 0;
}