版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lingzidong/article/details/82747452
题目链接:https://nanti.jisuanke.com/t/31714
题意就是给一个树,一开始点权都是0,然后有4个操作:树上路径加,乘,取反,输出路径和。答案对2^64取模首先加法乘法结合在一起其实比较好解决,用好线段树标记就行。现在来解决取反的问题,如果一点点取反肯定超时,所以我们是否能将取反转化成简单的加乘操作。首先!x = (2 ^64 - 1) - x,其次 (!x) % (2 ^ 64-1) = (2 ^64 -1)*x % (2 ^ 64) ,代入。发现!x = (2 ^64-1)*x + (2 ^64-1), 这样就转化成了线性的操作。
当时应该选择写这道题,当时的确没有想到正确的更新方式,实际上应该多利用题目中给的特殊条件来判断这个题如何来写。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#define ll long long
#define ull unsigned long long
#define mask 0xffffffffffffffff
using namespace std;
const int MAXN = 1 << 17;
struct Edge
{
int to,next;
}edge[MAXN * 2];
int head[MAXN],tot;
int top[MAXN];
int fa[MAXN];
int deep[MAXN];
int num[MAXN];
int p[MAXN];
int fp[MAXN];
int son[MAXN];
int pos;
int n;
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
pos = 0;
memset(son,-1,sizeof(son));
}
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u,int pre,int d)
{
deep[u] = d;
fa[u] = pre;
num[u] = 1;
for(int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(v == pre) continue;
dfs(v,u,d+1);
num[u] += num[v];
if(son[u] == -1 || num[v] > num[son[u]])
{
son[u] = v;
}
}
}
void getpos(int u,int sp)
{
top[u] = sp;
p[u] = ++pos;
fp[p[u]] = u;
if(son[u] == -1) return;
getpos(son[u],sp);
for(int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(v != son[u] && v != fa[u])
getpos(v,v);
}
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
ull sum[MAXN<<2];
ull add[MAXN<<2],mul[MAXN<<2];
void push_up(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void push_down(int rt,int m)
{
if(add[rt] != 0 || mul[rt] != 1)
{
add[rt<<1] = (mul[rt] * add[rt<<1] + add[rt]);
add[rt<<1|1] = (mul[rt] * add[rt<<1|1] + add[rt]);
mul[rt<<1] = mul[rt<<1] * mul[rt];
mul[rt<<1|1] = mul[rt<<1|1] * mul[rt];
sum[rt<<1] = mul[rt]*sum[rt<<1] + add[rt]*(m - (m >>1));
sum[rt<<1|1] = mul[rt]*sum[rt<<1|1] + add[rt]*(m>>1);
mul[rt] = 1,add[rt] = 0;
}
}
void build(int l,int r,int rt)
{
add[rt] = 0;
mul[rt] = 1;
sum[rt] = 0;
if(l == r) return;
int mid = (l +r ) >> 1;
build(lson);
build(rson);
push_up(rt);
}
void update(int op,int L,int R,ull val,int l,int r,int rt)
{
if(L <= l && r <= R)
{
if(op == 1)
{
add[rt] *= val;
mul[rt] *= val;
sum[rt] *= val;
}
else
{
add[rt] += val;
sum[rt] += val*(r - l+1);
}
return;
}
push_down(rt,r - l +1);
int mid = (l +r)>>1;
if(L <= mid) update(op,L,R,val,lson);
if(R > mid) update(op,L,R,val,rson);
push_up(rt);
}
ull query(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
{
return sum[rt];
}
push_down(rt,r - l +1);
int mid = (l +r )>>1;
ull res = 0;
if(L <= mid) res += query(L,R,lson);
if(R > mid) res += query(L,R,rson);
return res;
}
void change(int u,int v,ull val,int op)
{
while(top[u] != top[v])
{
if(deep[top[u]] < deep[top[v]]) swap(u,v);
update(op,p[top[u]],p[u],val,1,n,1);
u = fa[top[u]];
}
if(deep[u] > deep[v]) swap(u,v);
update(op,p[u],p[v],val,1,n,1);
}
ull ask(int u,int v)
{
ull tmp = 0;
while(top[u] != top[v])
{
if(deep[top[u]] < deep[top[v]])
{
swap(u,v);
}
tmp += query(p[top[u]],p[u],1,n,1);
u = fa[top[u]];
}
if(deep[u] > deep[v]) swap(u,v);
tmp += query(p[u],p[v],1,n,1);
return tmp;
}
int main()
{
while(scanf("%d",&n) != EOF)
{
init();
for(int i = 2;i<=n;i++)
{
int b;
scanf("%d",&b);
addedge(b,i);
addedge(i,b);
}
dfs(1,1,0);
getpos(1,1);
build(1,n,1);
int q;
scanf("%d",&q);
while(q--)
{
int op,u,v;
ull x;
scanf("%d%d%d",&op,&u,&v);
if(op == 1 || op == 2)
{
scanf("%llu",&x);
change(u,v,x,op);
}
else if(op == 3)
{
change(u,v,mask,1);
change(u,v,mask,2);
}
else
{
printf("%llu\n",ask(u,v));
}
}
}
return 0;
}