(http://acm.hust.edu.cn/vjudge/contest/view.action?cid=106364#problem/D)
题意:一棵树,点权值,两种操作,1.修改u的权值成w,2.查询u,v,求w[i]*w[j],i,j满足i,j的路径与u,v相交。
解法:先求不相交的。
对于每个节点u , 记录两个值
1. sum[u] u子树w之和。
2. sim( sum[v]^2 ) v是u的轻儿子。
每次修改操作时,对1进行区间更新,更改的2的个数最多为lg(n)个,暴力更改。
每次查询操作,区间查询2,单点查询1,即可完成操作。
总结:感觉这种只记录轻儿子还是很套路的。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define inf 1e9
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }
#define clr(x, y) memset(x, y, sizeof x)
#define ll long long
#define ull unsigned long long
#define FOR(i,a,b) \
for(i=a;a=b;aint maxn = 1e5 + 30;
const int mod = 1e9+7;
struct sad{
int to,next;
}G[maxn<<1];
int h[maxn],si;
void add(int u,int v){
// printf("u %d v %d\n",u,v);
G[si].to=v;
G[si].next=h[u];
h[u]=si++;
}
int siz[maxn],dep[maxn];
int fa[maxn],son[maxn],top[maxn];
void dfs1(int u,int f,int d){
fa[u]=f;
dep[u]=d;
siz[u]=1;
son[u]=-1;
for(int i=h[u];~i;i=G[i].next)
{
int v = G[i].to;
if(v^f){
dfs1(v,u,d+1);
siz[u]+=siz[v];
if( son[u] == -1 || siz[son[u]] < siz[v] )
son[u] = v;
}
}
}
int p[maxn],fp[maxn],pos;
void dfs2(int u,int sf){
// printf("u %d sf %d son %d\n",u,sf,son[u]);
//if( u == 0 ) while(1);
top[u] = sf;
p[u] = pos++;
fp[p[u]]=u;
if(son[u]==-1) return ;
dfs2(son[u],sf);
for(int i=h[u];~i;i=G[i].next)
{
int v=G[i].to;
// debug(v);
if(son[u]!=v&&fa[u]!=v)
dfs2(v,v);
}
}
int rs[maxn];
void upp(int x,int p)
{
while(x<=pos)
{
rs[x] = ((rs[x]+p)%mod+mod)%mod;
x+=x&-x;
}
}
int get(int x)
{
int ret = 0;
while(x)
{
ret = (ret+rs[x])%mod;
x-=x&-x;
}
return ret;
}
int rs2[maxn];
void upp2(int x,int p)
{
while(x<=pos)
{
rs2[x] = ((rs2[x]+p)%mod+mod)%mod;
x+=x&-x;
}
}
int get2(int x)
{
int ret = 0;
while(x)
{
ret = (ret+rs2[x])%mod;
x-=x&-x;
}
return ret;
}
int SUM;
void Change(int u,int d)
{
SUM=(SUM+d)%mod;
while( u != -1 )
{
int f1 = top[u] , f = fa[f1];
int lastsum=get(p[f1]),sum;
// printf("u %d f1 %d d %d\n",u,f1,d);
upp(p[f1],d);
upp(p[u]+1,-d);
if( f != -1 )
{
sum = get(p[f1]);
int t = (ll)sum*sum%mod-(ll)lastsum*lastsum%mod;
t = (t%mod+mod)%mod;
upp2(p[f],t);
}
u = f;
}
}
int Query(int u,int v){
int f1 = top[u] , f2 = top[v];
int ret = 0;
while(f1^f2)
{
if( dep[f1] < dep[f2] )
{
swap(f1,f2);
swap(u,v);
}
ret = ((ret+get2(p[u])-get2(p[f1]-1))%mod+mod)%mod;
int t = get(p[f1]);
ret = ((ret-(ll)t*t%mod)%mod+mod)%mod;
if( son[u] != -1 ){
int t = get(p[son[u]]);
ret = ((ret+(ll)t*t%mod)%mod+mod)%mod;
}
u = fa[f1];
f1 = top[u];
}
if( dep[u] > dep[v] ) swap(u,v);
ret = ((ret+get2(p[v])-get2(p[u]-1))%mod+mod)%mod;
if( son[v] != -1 ){
int t = get(p[son[v]]);
ret = ((ret+(ll)t*t%mod)%mod+mod)%mod;
}
int t = SUM - get(p[u]);
ret = (ret+(ll)t*t%mod)%mod;
ret = ( (ll)SUM*SUM%mod - ret ) % mod;
return (ret+mod)%mod;
}
void init()
{
clr(h,-1);
si=0;
pos=1;
}
int w[maxn];
int main()
{
//freopen("input.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
int u,v;
for(int i=0;i1;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(1,-1,1);
dfs2(1,1);
clr(rs,0);
clr(rs2,0);
SUM=0;
for(int i=1;i<=n;i++)
Change(i,w[i]);
/*for(int i=1;i<=n;i++)
printf("i %d sum %d\n",i,get(p[i]));*/
int a,b,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if( a == 1 )
{
Change(b,(c-w[b]+mod)%mod);
w[b] = c;
}else
printf("%d\n",Query(b,c));
}
}
return 0;
}