E-Jiu Yuan Wants to Eat
题目链接:https://nanti.jisuanke.com/t/31714
题意:树链剖分4种操作:
1 u到v的节点同时乘上x
2 u到v的节点同时加上x
3 u到v的节点全部64位无符号整型取反
4 求u到v节点的和
树链剖分学了又忘了,来复习一哈
dfs2
从①开始,一直走,走最长的链走不动了才回头,回头的时候先遇上⑥,然后⑥作为新的起始重节点又继续往下走,走不动了才回头,然后回头的时候又遇上⑦,这样一直下去
UpdateNode
假如他们就在一条链上面,那简单,排的名次是连续的,深度浅一点的排前面
不在一条链上的就麻烦一点了:
假如要在⑦到⑧节点加权值,先找这两条链的起始重节点,看谁的深度深就先处理谁的,这就好像是先把树的枝条处理了,然后再处理树的主干,起始重节点越深的就越像是树的枝条,而树的主干的起始重节点肯定是最上面,也就是深度最浅的
就像图上这样,先处理黄色的,然后③和⑦比较谁更“枝条”一些就先处理谁
#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn=2e5+5;
const int MOD=1e9+7;
int N,Q;
struct Edge
{
int t,v,nxt;
};
Edge E[maxn<<1];
int head[maxn];
int tot;
void AddEdge(int aa,int bb,int val)
{
E[++tot].t=bb;
E[tot].v=val;
E[tot].nxt=head[aa];
head[aa]=tot;
}
int sz[maxn],fa[maxn],dep[maxn],son[maxn];
void dfs1(int u,int pre,int deep)//处理出节点u的深度dep[u],节点大小sz[u],重儿子son[u]
{
dep[u]=deep;
sz[u]=1;
fa[u]=pre;
for(int i=head[u]; i!=-1; i=E[i].nxt)
{
int t=E[i].t;
if(t==pre)continue;
dfs1(t,u,deep+1);
if(son[u]==-1)son[u]=t;//如果u暂时没有重儿子,那么t就是u的重儿子
else if(sz[t]>sz[son[u]])son[u]=t;//如果当前这个儿子t比原来的还重,那就更新
sz[u]+=sz[t];
}
}
int sa[maxn],rnk[maxn],top[maxn],Time;
void dfs2(int u,int pre,int uu)//处理出u节点的排名rnk[u],sa[u],以及u节点的起始重节点top[u]
{
rnk[u]=++Time;
sa[Time]=u;
top[u]=uu;
if(son[u]!=-1)dfs2(son[u],u,uu);//先一直往下走,把最长的先找出来
for(int i=head[u]; i!=-1; i=E[i].nxt)
{
int t=E[i].t;
if(t==pre)continue;
if(son[u]!=t)dfs2(t,u,t);//如果t这个儿子不是重儿子,那么这个儿子就成了新的起始节点
}
}
ull sum[maxn<<2],Add[maxn<<2],Mul[maxn<<2];
void pushup(int id)
{
sum[id]=sum[id<<1]+sum[id<<1|1];
}
void pushdown(int id,int L,int R)
{
if(Add[id]!=(ull)0||Mul[id]!=(ull)1)
{
Add[id<<1]=Add[id<<1]*Mul[id]+Add[id];
Add[id<<1|1]=Add[id<<1|1]*Mul[id]+Add[id];
Mul[id<<1]*=Mul[id];
Mul[id<<1|1]*=Mul[id];
int mid=L+R>>1;
sum[id<<1]=sum[id<<1]*Mul[id]+Add[id]*(mid-L+1);
sum[id<<1|1]=sum[id<<1|1]*Mul[id]+Add[id]*(R-mid);
Add[id]=0;
Mul[id]=1;
}
}
void Build(int id,int L,int R)
{
sum[id]=0;
Add[id]=0;
Mul[id]=1;
if(L==R)return;
else
{
int mid=L+R>>1;
Build(id<<1,L,mid);
Build(id<<1|1,mid+1,R);
pushup(id);
}
}
void Update(int id,int L,int R,int qL,int qR,ull add,ull mul)
{
if(qL<=L&&qR>=R)
{
sum[id]=sum[id]*mul+add*(R-L+1);
Mul[id]*=mul;
Add[id]=Add[id]*mul+add;
}
else
{
pushdown(id,L,R);
int mid=L+R>>1;
if(qL<=mid) Update(id<<1,L ,mid,qL,qR,add,mul);
if(qR>=mid+1)Update(id<<1|1,mid+1,R ,qL,qR,add,mul);
pushup(id);
}
}
ull query(int id,int L,int R,int qL,int qR)
{
if(qL<=L&&qR>=R)return sum[id];
else
{
pushdown(id,L,R);
ull res=0;
int mid=L+R>>1;
if(qL<=mid) res+=query(id<<1 ,L ,mid,qL,qR);
if(qR>=mid+1)res+=query(id<<1|1,mid+1,R ,qL,qR);
return res;
}
}
void UpdateNode(int u,int v,ull add,ull mul)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);//谁的起始重节点深度深,谁就更"枝条",就先处理谁
Update(1,1,N,rnk[top[u]],rnk[u],add,mul);
u=fa[top[u]];
}
if(rnk[u]>rnk[v])swap(u,v);
Update(1,1,N,rnk[u],rnk[v],add,mul);
}
ull queryNode(int u,int v)
{
ull res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);//谁的起始重节点深度深,谁就更"枝条",就先处理谁
ull tp=query(1,1,N,rnk[top[u]],rnk[u]);
res+=tp;
u=fa[top[u]];
}
if(rnk[u]>rnk[v])swap(u,v);
ull tp=query(1,1,N,rnk[u],rnk[v]);
res+=tp;
return res;
}
int main()
{
ull MAX;
memset(&MAX,-1,sizeof MAX);
while(cin>>N)
{
tot=Time=0;
memset(head,-1,sizeof head);
memset(son,-1,sizeof son);
for(int i=2; i<=N; i++)
{
int t;
scanf("%d",&t);
AddEdge(i,t,1);
AddEdge(t,i,1);
}
dfs1(1,-1,1);
dfs2(1,-1,1);
Build(1,1,N);
scanf("%d",&Q);
while(Q--)
{
int cmd,u,v;
ull x;
scanf("%d%d%d",&cmd,&u,&v);
if(cmd==1)
{
scanf("%lld",&x);
UpdateNode(u,v,0,x);
}
else if(cmd==2)
{
scanf("%lld",&x);
UpdateNode(u,v,x,1);
}
else if(cmd==3)
{
UpdateNode(u,v,MAX,MAX);
}
else
{
printf("%llu\n",queryNode(u,v));
}
}
}
}
打印
void print()
{
for(int i=1; i<=N; i++)cout<<"u="<<i<<" rnk="<<rnk[i]<<" sa="<<sa[i]<<" son="<<son[i]<<" top="<<top[i]<<endl;
}
void printTree()
{
for(int i=1; i<4*N; i++)
{
cout<<"id="<<i<<" Add="<<Add[i]<<" Mul="<<Mul[i]<<" sum="<<sum[i]<<" | ";
if((i&(i+1))==0)puts("");
}
puts("");
}