题目链接:点击这里
解题思路:
如果这题只有乘法和加法操作那么我们可以直接套树链剖分 + 多重标记,那么我们就想办法把取反变为加法和乘法.
!x = (2^64-1) - x, -x % (2^64) = (2^64-1)*x % (2^64) , !x = (2^64-1)*x + (2^64-1)
这样就把取反也转化成加法和乘法的操作啦.
而且我们并不需要去快速乘,因为数值溢出时就是变为取模 2^64 的值
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mx = 1e5 + 10;
const ull M = -1;
int num[mx],n,head[mx],tot,fa[mx];
int siz[mx],dep[mx],size,top[mx];
int cost[mx];
int L,R,d;
ull sum[mx*3],add[mx*3],mul[mx*3],k;
struct node
{
int son,nxt;
}Edge[mx<<1];
void AddEdge(int x,int y)
{
Edge[tot].son = y;
Edge[tot].nxt = head[x];
head[x] = tot++;
}
void dfs1(int x,int f)//求重儿子,深度,树大小等等
{
dep[x] = dep[f] + 1;
siz[x] = 1;
int p = 0,wei = 0;
for(int i=head[x];~i;i=Edge[i].nxt)
{
int son = Edge[i].son;
if(son==f) continue;
fa[son] = x;
dfs1(son,x);
siz[x] += siz[son];
if(siz[son]>siz[wei]) wei = son,p = i;
}
//把重儿子换到第一个
if(p) swap(Edge[head[x]].son,Edge[p].son);
}
void dfs2(int x,int f)//重链轻链编号
{
num[x] = ++size;
for(int i=head[x];~i;i=Edge[i].nxt)
{
int son = Edge[i].son;
if(son==f) continue;
if(i==head[x]) top[son] = top[x];//是不是重儿子
else top[son] = son;
dfs2(son,x);
}
}
void push_down(int l,int r,int rt)
{
mul[rt<<1] = mul[rt<<1]*mul[rt];
mul[rt<<1|1] = mul[rt<<1|1]*mul[rt];
add[rt<<1] = add[rt<<1]*mul[rt]+add[rt];
add[rt<<1|1] = add[rt<<1|1]*mul[rt]+add[rt];
int mid = (l+r)>>1;
sum[rt<<1] = sum[rt<<1]*mul[rt] + add[rt]*(mid-l+1);
sum[rt<<1|1] = sum[rt<<1|1]*mul[rt] + add[rt]*(r-mid);
mul[rt] = 1,add[rt] = 0;
}
void update(int l,int r,int rt)
{
if(L<=l&&r<=R){
if(d==1){
mul[rt] = mul[rt]*k;
add[rt] = add[rt]*k;
sum[rt] = sum[rt]*k;
}else{
add[rt] = add[rt]+k;
sum[rt] = sum[rt]+k*(r-l+1);
}
return ;
}
push_down(l,r,rt);
int mid = (l+r)>>1;
if(L<=mid) update(lson);
if(R>mid) update(rson);
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
ull query(int l,int r,int rt)
{
if(L<=l&&r<=R) return sum[rt];
push_down(l,r,rt);
int mid = (l+r)>>1;
ull ans = 0;
if(L<=mid) ans += query(lson);
if(R>mid) ans += query(rson);
return ans;
}
void build(int l,int r,int rt)
{
sum[rt] = add[rt] = 0;
mul[rt] = 1;
if(l==r) return ;
int mid = (l+r)>>1;
build(lson);
build(rson);
}
void init()
{
memset(head,-1,sizeof(head));
size = tot = 0;
top[1] = 1;
build(1,n,1);
}
void mask(int x,int y,int s,ull& ans)
{
int f1 = top[x],f2 = top[y];
while(f1!=f2){//log(n)刨链更新
if(dep[f1]>=dep[f2]){
L = num[f1],R = num[x];
x = fa[f1],f1 = top[x];
}else{
L = num[f2],R = num[y];
y = fa[f2],f2 = top[y];
}
if(s) ans += query(1,n,1);
else update(1,n,1);
}
L = min(num[x],num[y]);
R = max(num[x],num[y]);
if(s) ans += query(1,n,1);
else update(1,n,1);
}
int main()
{
while(~scanf("%d",&n)){
init();
for(int i=2;i<=n;i++){
scanf("%d",&d);
AddEdge(d,i);
}
dfs1(1,0),dfs2(1,0);
int q,x,y;
scanf("%d",&q);
while(q--){
scanf("%d",&d);
ull ans = 0;
if(d==4){
scanf("%d%d",&x,&y);
mask(x,y,1,ans);
printf("%llu\n",ans);
}else{
if(d==3){
scanf("%d%d",&x,&y);
k = M,d = 1;
mask(x,y,0,ans);
d = 2,mask(x,y,0,ans);
}else{
scanf("%d%d%llu",&x,&y,&k);
mask(x,y,0,ans);
}
}
}
}
return 0;
}