F A Simple Problem On A Tree
题意:一棵树,有权值,4种操作,
1:u,v路径上的点权值全部为w
2:u,v路径上的点权值全部加w
3:u,v路径上的点权值全部乘w
4:u,v路径上的点
w
3
w^3
w3和
思路:
首先肯定是要把树上的操作转换为连续区间,所以(树)刨一下,然后接下来就是线段树操作了。
线段树操作:
求
w
3
w^3
w3的和,所以我们维护一个sum3,表示
w
3
w^3
w3。建树pushup(初始情况)
然后对于更新操作,假设a,b,c,加上x,
(
a
+
x
)
3
+
(
b
+
x
)
3
+
(
c
+
x
)
3
=
a
3
+
b
3
+
c
3
+
3
∗
x
∗
(
a
2
+
b
2
+
c
2
)
+
3
∗
x
2
∗
(
a
+
b
+
c
)
+
3
∗
x
3
(a+x)^3 + (b + x)^3 + (c + x )^3 = a^3 + b^3 + c^3 +3*x*(a^2 + b^2 + c^2) + 3*x^2*(a+ b + c) + 3*x^3
(a+x)3+(b+x)3+(c+x)3=a3+b3+c3+3∗x∗(a2+b2+c2)+3∗x2∗(a+b+c)+3∗x3
然后我们再维护一个sum2(
w
2
w^2
w2),sum1(
w
w
w),进行区间加的时候直接加上这个式子就ok。
对于乘法的话,我们只需要把这个区间的sum3*
x
3
x^3
x3就是了。
然后对于操作1,我们先对这个区间乘以0,在加上w。
对于lazy标记
有2个(乘法,除法)标记,ad = 0,mu = 1.
然后我们是先乘还是先加?
假设我们先乘在加。
(a + x)y = ay + x*y
所以我们还是先区间乘上y,然后把这个区间的ad乘上y,用更新过的ad去进行加的操作
先加在乘的话就可以依次进行。
Code(1989ms)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
//#define int long long
vector<int>sp[man];
int va[man];
int top[man],rk[man],id[man],siz[man];
int son[man],fa[man],dep[man];
int cnt = 0;
void dfs1(int u,int f){
siz[u] = 1;
fa[u] = f;
dep[u] = dep[f] + 1;
for(int i = 0;i < sp[u].size();i++){
int v = sp[u][i];
if(v==f)continue;
dfs1(v,u);
siz[u] += siz[v];
if(siz[son[u]]<siz[v]){
son[u] = v;
}
}
}
void dfs2(int u,int tp){
id[++cnt] = u;
rk[u] = cnt;
top[u] = tp;
if(!son[u])return;
dfs2(son[u],tp);
for(int i = 0;i < sp[u].size();i++){
int v = sp[u][i];
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
ll sum1[man<<2],sum2[man<<2],sum3[man<<2];
int ad[man<<2],mu[man<<2];
inline void add(ll &x, int y){
(x += y) >= mod ? x -= mod : x;
}
inline void mul(ll &x, int y){
x = 1ll * x * y % mod;
}
void pushup(int rt){
sum1[rt] = (sum1[rt<<1] + sum1[rt<<1|1])%mod;
sum2[rt] = (sum2[rt<<1] + sum2[rt<<1|1])%mod;
sum3[rt] = (sum3[rt<<1] + sum3[rt<<1|1])%mod;
}
inline void pushdown1(int rt,int x,int y,int num){
if(y!=1){//*
int w1 = y;
int w2 = 1ll*y*y%mod;
int w3 = 1ll*w2*y%mod;
mul(sum1[rt],w1);
mul(sum2[rt],w2);
mul(sum3[rt],w3);
mu[rt] = 1ll*mu[rt]*y%mod;
ad[rt] = 1ll*ad[rt]*y%mod;
}
if(x!=0){//+
int w1 = x;
int w2 = 1ll*x*x%mod;
int w3 = 1ll*w2*x%mod;
add(sum3[rt],3ll*w1%mod*sum2[rt]%mod);
add(sum3[rt],3ll*w2%mod*sum1[rt]%mod);
add(sum3[rt],1ll*num*w3%mod);
add(sum2[rt],1ll*num*w2 % mod);
add(sum2[rt],2LL*w1*sum1[rt] % mod);
add(sum1[rt],1ll*num*w1%mod);
ad[rt] = (1ll*ad[rt] + w1)%mod;
}
}
inline void pushdown(int rt,int ls,int rs){
int x = ad[rt];
int y = mu[rt];
pushdown1(rt<<1,x,y,ls);
pushdown1(rt<<1|1,x,y,rs);
ad[rt] = 0;
mu[rt] = 1;
}
inline void build(int l,int r,int rt){
sum1[rt] = sum2[rt] = sum3[rt] = 0;
ad[rt] = 0;
mu[rt] = 1;
if(l==r){
//cout << "l:" << l << " " << id[l] << endl;
sum1[rt] = va[id[l]];
sum2[rt] = 1ll * va[id[l]] * va[id[l]] % mod;
sum3[rt] = 1ll * sum2[rt] * va[id[l]] % mod;
return;
}
int m = l + r >> 1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
inline void update(int l,int r,int L,int R,int rt,int op,int v){
if(L<=l&&R>=r){
//更新
if(op==1){
pushdown1(rt,v,0,r - l + 1);
}else if(2==op){
pushdown1(rt,v,1,r - l + 1);
}else{
pushdown1(rt,0,v,r - l + 1);
}
return;
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
if(L<=m)update(l,m,L,R,rt<<1,op,v);
if(R>m)update(m+1,r,L,R,rt<<1|1,op,v);
pushup(rt);
}
inline int query(int l,int r,int L,int R,int rt){
if(L<=l&&R>=r){
//cout << l << " l:r " << r << " " << L << " L:R " << R <<endl;
return sum3[rt];
}
int m = l + r >> 1;
pushdown(rt,m-l+1,r-m);
int ans = 0;
if(L<=m)ans = (ans + query(l,m,L,R,rt<<1))%mod;
if(R>m)ans = (ans + query(m+1,r,L,R,rt<<1|1))%mod;
pushup(rt);
return ans;
}
void update(int u,int v,int op,int V){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]){
swap(u,v);
}
update(1,cnt,rk[top[u]],rk[u],1,op,V);
u = fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(1,cnt,rk[v],rk[u],1,op,V);
}
ll query(int u,int v){
ll ans = 0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]){
swap(u,v);
}
int tp = query(1,cnt,rk[top[u]],rk[u],1);
add(ans,tp);
//cout <<"u:" << u << " " << v << " " << top[u] << " " << u << " " << ans << "tp:" << tp << endl;
u = fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
add(ans,query(1,cnt,rk[v],rk[u],1));
//cout <<"u:" << u << " " << v << " " << top[u] << " " << u <<" " << ans << endl;
return ans;
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t,T = 0;
scanf("%d",&t);
//cout << t << endl;
while(t--){
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)sp[i].clear(),son[i] = 0;
for(int i = 1;i < n;i++){
int u,v;
scanf("%d%d",&u,&v);
sp[u].push_back(v);
sp[v].push_back(u);
}
for(int i = 1;i <= n;i++)scanf("%d",&va[i]);
dep[0] = 0;cnt = 0;
dfs1(1,0);
dfs2(1,1);
build(1,cnt,1);
//cout << "!!!!" << endl;
printf("Case #%d: \n",++T);
int q;scanf("%d",&q);
while(q--){
int op,u,v,w;
scanf("%d",&op);
scanf("%d%d",&u,&v);
if(4!=op){
scanf("%d",&w);
update(u,v,op,w);
}else{
printf("%d\n",query(u,v));
}
}
}
return 0;
}