リンク:https://ac.nowcoder.com/acm/contest/180/E
出典:牛オフネットワーク
ツリーパス
期限:C / C ++ 2秒、4秒の言語他の
空間制限:C / C ++ 262144K、他の言語の524288Kの
64ビットIO形式:%LLDの
主題記述が
ツリーのn個の点について説明するが、ルートノードは、番号1であります各点は、重量有する
次サポートする必要
uがノードをルートとするサブツリーは、(Uを含む)する1追加ウェイトヴァル
2の右ノード(U、V)に加えてパスのvalの値
3.経路及びペアワイズの値(U、V)を右のノードを尋ねます
入力説明:
二つの整数N、Mの最初の行は、操作の数、ツリーのノードの数を表します
次に、行数n、各ノードの重みの値
次のn - 1の間の2つの整数(U、V)、(U、V)で表される側ラインを有しています
その後、第m行目は、
いくつかのOPTを開始し、操作の種類を示す
ときOPT = 1、次の2つの整数U valが、
OPT = 2、次の3つの整数(U、V)、ヴァルで表される場合
、OPT = 3の場合、次の2つの整数(U、V)
タイトルに示されているような意味であり
、出力の説明:
10 ^ 9 + 710への第3の動作の各々について、出力応答によって表される数
9
+7モジュロ
例1つ
の入力は
コピー
38
5 3 1
1 2
1 3
3 1 2
3 1 3
3 2 3
。1 1 2
2 2 3 1
3 1 2
3 1 3
3 2 3
出力
コピー
15
5
23である
45
45
115
記載の
クエリ結果の最初のセット:3 * 5 15 =
問い合わせ結果の第二群:5 = 1×5
5 + 1 * 3 * 3 * 5 + 1 = 23:クエリ結果の第三のセット
注
30%30データの%、N、Mの\ leqslantの100N、のため m⩽100
\ ^ 5N 10 leqslant 100%〜100%、N-、M、m⩽10へのデータ
。5
提供a_ia
私はそのa_iを\ ^ 10(a)のleqslant確実にするために、各変形読み出しノードiと重みの重量を表し、iは⩽10を。4
否定がないことを確認するために、
アイデア:
チェーンツリーはタイトルを分割することは明らかです、
最初の二つの動作は、通常動作のツリーの分割鎖であります
私たちは、3つのディレクトリの操作を見て、我々はルート照会上の3つのノードがあることを前提とし、重みは、A、B、Cです,,結果は、我々が尋ねることであるBのA +どのように用語C + B * cをこの結果を得ますか?
乗算の二十個を加えた結果、すなわち、我々は、間隔を導出するために、2つの間隔の値(合計値とノードの重みとノードの重みの二乗の和)を維持することができる(すなわち、操作3の出力)。
私たちは、ここで私は、その後、どのようにそれがある(それの重量の二乗和を維持するために、話すことはありません、そのツリーラインのメンテナンス間隔の合計を知っているし、非常に簡単であるとき、それは新しい正方形の和を取得することがいかに簡単か間隔の各値プラストン、 )?
我々は、重みは、B、Cの3つのノードの変更区間であると仮定する
二乗和を更新するための和と二乗和:このように我々は、ツリーラインから2つの値を維持できることがわかります
例えば、インターバルプラストンのために
体重和と乗算することにより二乗和=新しい更新間隔の長さの時間t + T + 2Tの二乗和の前に。
あなたは、この質問を書く過ごすことができるように、ツリーラインは、+ =の代わりに=のものでなければならないとき、マークプッシュダウンを覚えて
詳細コードを参照してください。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
const ll mod=1e9+7ll;
std::vector<int> son[maxn];
ll w[maxn];
ll wt[maxn];
int id[maxn];
int SZ[maxn];
int wson[maxn];
int top[maxn];
int fa[maxn];
int n,m;
int dep[maxn];
int cnt;
void init()
{
cnt=0;
}
void dfs1(int x,int pre,int step)
{
fa[x]=pre;
dep[x]=step;
SZ[x]=1;
int maxson=-1;
for(auto & t:son[x])
{
if(t!=pre)
{
dfs1(t,x,step+1);
SZ[x]+=SZ[t];
if(SZ[t]>maxson)
{
maxson=SZ[t];
wson[x]=t;
}
}
}
}
void dfs2(int x,int topf)
{
top[x]=topf;
id[x]=++cnt;
wt[cnt]=w[x];
if(wson[x])
dfs2(wson[x],topf);
else
return ;
for(auto &t :son[x])
{
if(t==wson[x]||t==fa[x])
{
continue;
}
dfs2(t,t);
}
}
struct node
{
ll l,r;
ll sum;
ll csum;
ll laze;
}segment_tree[maxn<<2];
void pushup(int rt)
{
segment_tree[rt].sum=(segment_tree[rt<<1].sum+segment_tree[rt<<1|1].sum)%mod;
segment_tree[rt].csum=(segment_tree[rt<<1].csum+segment_tree[rt<<1|1].csum)%mod;
}
void build(int rt,int l,int r)
{
segment_tree[rt].l=l;
segment_tree[rt].r=r;
segment_tree[rt].laze=0ll;
if(l==r)
{
segment_tree[rt].sum=wt[l];
segment_tree[rt].csum=wt[l]*wt[l]%mod;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void pushdown(int rt)
{
if(segment_tree[rt].laze)
{
ll val=segment_tree[rt].laze%mod;
segment_tree[rt].laze=0ll;
segment_tree[rt<<1].csum+=((segment_tree[rt<<1].r-segment_tree[rt<<1].l+1)*val%mod*val%mod+2ll*val%mod*(segment_tree[rt<<1].sum)%mod)%mod;
segment_tree[rt<<1].csum%=mod;
segment_tree[rt<<1].sum+=(segment_tree[rt<<1].r-segment_tree[rt<<1].l+1)*val%mod;
segment_tree[rt<<1].sum%=mod;
segment_tree[rt<<1].laze+=val;
segment_tree[rt<<1].laze%=mod;
segment_tree[rt<<1|1].csum+=((segment_tree[rt<<1|1].r-segment_tree[rt<<1|1].l+1)*val%mod*val%mod+2ll*val%mod*(segment_tree[rt<<1|1].sum)%mod)%mod;
segment_tree[rt<<1|1].csum%=mod;
segment_tree[rt<<1|1].sum+=(segment_tree[rt<<1|1].r-segment_tree[rt<<1|1].l+1)*val%mod;
segment_tree[rt<<1|1].sum%=mod;
segment_tree[rt<<1|1].laze+=val;
segment_tree[rt<<1|1].laze%=mod;
}
}
void update(int rt,int l,int r,ll val)
{
val%=mod;
if(segment_tree[rt].l>=l&&segment_tree[rt].r<=r)
{
segment_tree[rt].csum+=((segment_tree[rt].r-segment_tree[rt].l+1)*val%mod*val%mod+2ll*val%mod*segment_tree[rt].sum%mod)%mod;
segment_tree[rt].csum%=mod;
segment_tree[rt].laze+=val;
segment_tree[rt].laze%=mod;
segment_tree[rt].sum+=(segment_tree[rt].r-segment_tree[rt].l+1)*val%mod;
segment_tree[rt].sum%=mod;
return ;
}
pushdown(rt);
int mid=segment_tree[rt].r+segment_tree[rt].l;
mid>>=1;
if(mid>=l)
{
update(rt<<1,l,r,val);
}
if(mid<r)
{
update(rt<<1|1,l,r,val);
}
pushup(rt);
}
void upson(int x,ll val)
{
val%=mod;
update(1,id[x],id[x]+SZ[x]-1,val);
}
void uprange(int x,int y,ll val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
update(1,id[top[x]],id[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y])
{
swap(x,y);
}
update(1,id[x],id[y],val);
}
ll ask1(int rt,int l,int r)
{
if(segment_tree[rt].l>=l&&segment_tree[rt].r<=r)
{
return segment_tree[rt].sum%mod;
}
pushdown(rt);
int mid=(segment_tree[rt].l+segment_tree[rt].r)>>1;
ll res=0ll;
if(mid>=l)
{
res+=ask1(rt<<1,l,r);
res%=mod;
}
if(mid<r)
{
res+=ask1(rt<<1|1,l,r);
res%=mod;
}
return res;
}
ll ask2(int rt,int l,int r)
{
if(segment_tree[rt].l>=l&&segment_tree[rt].r<=r)
{
return segment_tree[rt].csum%mod;
}
pushdown(rt);
int mid=(segment_tree[rt].l+segment_tree[rt].r)>>1;
ll res=0ll;
if(mid>=l)
{
res+=ask2(rt<<1,l,r);
res%=mod;
}
if(mid<r)
{
res+=ask2(rt<<1|1,l,r);
res%=mod;
}
return res;
}
ll qrange(int x,int y)
{
ll sum1=0ll;
ll sum2=0ll;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
sum1=(sum1+ask1(1,id[top[x]],id[x]))%mod;
sum2=(sum2+ask2(1,id[top[x]],id[x]))%mod;
x=fa[top[x]];
}
if(dep[x]>dep[y])
{
swap(x,y);
}
sum1=(sum1+ask1(1,id[x],id[y]))%mod;
sum2=(sum2+ask2(1,id[x],id[y]))%mod;
ll res=(sum1*sum1%mod-sum2+mod)%mod;
res=(res*powmod(2ll,mod-2ll,mod))%mod;
return res;
}
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
gbtb;
cin>>n>>m;
repd(i,1,n)
{
cin>>w[i];
}
int u,v;
repd(i,2,n)
{
cin>>u>>v;
son[u].pb(v);
son[v].pb(u);
}
init();
dfs1(1,-1,0);
dfs2(1,1);
build(1,1,n);
int op;
ll c;
while(m--)
{
cin>>op;
if(op==1)
{
cin>>u>>c;
upson(u,c);
}else if(op==2)
{
cin>>u>>v>>c;
uprange(u,v,c);
}else if(op==3)
{
cin>>u>>v;
cout<<qrange(u,v)<<endl;
}
}
return 0;
}
inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}