Nowcoder练习赛26 E 树上路径
Captain_Paul
2018-09-07 21:09:15
题意:一棵树,支持三种操作:
- 子树加上一个值
- 路径加上一个值
- 询问一条路径上任取两个数的乘积的总和
------------
前两个操作好办,就是树剖模板
第三个操作让我联想到了P4247 序列操作
但是因为序列转移到了树上,所以没法直接套用
那不会是LCT吧?应该不是。。
其实很简单,我们只要树剖之后线段树维护**区间总和**和**区间平方和**就好了
因为最后的答案可以进行化简
比如说区间长度为3,三个数分别为$a,b,c$
那么所求答案为$ab+ac+bc$
经过一波操作可以发现ta其实是$[(a+b+c)^2-a^2-b^2-c^2]/2$
其他情况同理
然后只要注意$pushdown$的时候区间加法对子区间的影响就好了
~~还是Jan神NB啊~~ orzorz
贴上代码(取模不到位还WA了两发)
```
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define reg register
using namespace std;
typedef long long ll;
const int N=1e5+5,mod=1e9+7,inv2=5e8+4;
struct node
{
int to,nxt;
}edge[N<<1];
int n,m,num,head[N],fa[N],son[N],dep[N],tot[N];
int cnt,idx[N],top[N],a[N],w[N];
ll sum1[N<<2],sum2[N<<2],tag[N<<2];
inline int read()
{
int x=0,w=1;
char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),w=-1;
while (isdigit(c))
{
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*w;
}
inline void add_edge(int from,int to)
{
edge[++num]=(node){to,head[from]};
head[from]=num;
}
void dfs(int k,int father,int deep)
{
int bigson=0;
fa[k]=father; dep[k]=deep; tot[k]=1;
for (reg int i=head[k];i;i=edge[i].nxt)
{
int v=edge[i].to;
if (v==father) continue;
dfs(v,k,deep+1); tot[k]+=tot[v];
if (bigson<tot[v]) bigson=tot[v],son[k]=v;
}
}
void dfs(int k,int tp)
{
idx[k]=++cnt; top[k]=tp; a[cnt]=k;
if (!son[k]) return; dfs(son[k],tp);
for (reg int i=head[k];i;i=edge[i].nxt)
{
int v=edge[i].to;
if (!idx[v]) dfs(v,v);
}
}
inline void pushup(int now)
{
sum1[now]=(sum1[now<<1]+sum1[now<<1|1])%mod;
sum2[now]=(sum2[now<<1]+sum2[now<<1|1])%mod;
}
inline void pushdown(int now,int l,int r)
{
if (!tag[now]) return;
tag[now<<1]=(tag[now<<1]+tag[now])%mod; tag[now<<1|1]=(tag[now<<1|1]+tag[now])%mod;
sum2[now<<1]=(sum2[now<<1]+1ll*tag[now]*tag[now]*l+2ll*tag[now]*sum1[now<<1])%mod;
sum2[now<<1|1]=(sum2[now<<1|1]+1ll*tag[now]*tag[now]*r+2ll*tag[now]*sum1[now<<1|1])%mod;
sum1[now<<1]=(sum1[now<<1]+1ll*tag[now]*l)%mod; sum1[now<<1|1]=(sum1[now<<1|1]+1ll*tag[now]*r)%mod;
tag[now]=0;
}
void build(int l,int r,int now)
{
if (l==r)
{
sum1[now]=1ll*w[a[l]]%mod;
sum2[now]=1ll*w[a[l]]*w[a[l]]%mod;
return;
}
int mid=(l+r)>>1;
build(l,mid,now<<1);
build(mid+1,r,now<<1|1);
pushup(now);
}
void inchange(int L,int R,int l,int r,int now,int c)
{
if (l>R||r<L) return;
if (l>=L&&r<=R)
{
sum2[now]=(sum2[now]+1ll*c*c*(r-l+1)+2ll*c*sum1[now])%mod;
sum1[now]=(sum1[now]+1ll*c*(r-l+1))%mod; tag[now]=(tag[now]+c)%mod; return;
}
int mid=(l+r)>>1; pushdown(now,mid-l+1,r-mid);
if (mid>=R) inchange(L,R,l,mid,now<<1,c);
else if (mid<L) inchange(L,R,mid+1,r,now<<1|1,c);
else
{
inchange(L,mid,l,mid,now<<1,c);
inchange(mid+1,R,mid+1,r,now<<1|1,c);
}
pushup(now);
}
ll ingetsum1(int L,int R,int l,int r,int now)
{
if (l>R||r<L) return 0;
if (l>=L&&r<=R) return sum1[now]%mod;
int mid=(l+r)>>1; pushdown(now,mid-l+1,r-mid);
if (mid>=R) return ingetsum1(L,R,l,mid,now<<1);
if (mid<L) return ingetsum1(L,R,mid+1,r,now<<1|1);
return (ingetsum1(L,mid,l,mid,now<<1)+ingetsum1(mid+1,R,mid+1,r,now<<1|1))%mod;
}
ll ingetsum2(int L,int R,int l,int r,int now)
{
if (l>R||r<L) return 0;
if (l>=L&&r<=R) return sum2[now]%mod;
int mid=(l+r)>>1; pushdown(now,mid-l+1,r-mid);
if (mid>=R) return ingetsum2(L,R,l,mid,now<<1);
if (mid<L) return ingetsum2(L,R,mid+1,r,now<<1|1);
return (ingetsum2(L,mid,l,mid,now<<1)+ingetsum2(mid+1,R,mid+1,r,now<<1|1))%mod;
}
inline void treechange(int x,int y,int val)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
inchange(idx[top[x]],idx[x],1,n,1,val);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
inchange(idx[x],idx[y],1,n,1,val);
}
inline ll treesum1(int x,int y)
{
ll ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=(ans+ingetsum1(idx[top[x]],idx[x],1,n,1))%mod;
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
ans=(ans+ingetsum1(idx[x],idx[y],1,n,1))%mod;
return ans;
}
inline ll treesum2(int x,int y)
{
ll ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=(ans+ingetsum2(idx[top[x]],idx[x],1,n,1))%mod;
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
ans=(ans+ingetsum2(idx[x],idx[y],1,n,1))%mod;
return ans;
}
int main()
{
n=read(),m=read();
for (reg int i=1;i<=n;w[i++]=read());
for (reg int i=1;i<n;i++)
{
int x=read(),y=read();
add_edge(x,y); add_edge(y,x);
}
dfs(1,0,1); dfs(1,1); build(1,n,1);
while (m--)
{
int opt=read(),x=read(),y=read();
if (opt==1) inchange(idx[x],idx[x]+tot[x]-1,1,n,1,y);
if (opt==2) treechange(x,y,read());
if (opt==3)
{
ll sum11=treesum1(x,y),sum22=treesum2(x,y);
ll ans=((sum11*sum11-sum22)%mod*inv2%mod+mod)%mod;
printf("%lld\n",ans);
}
}
return 0;
}
```