HDU 5405 Sometimes Naive 树链剖分+bit*****
Sometimes Naive
Problem Description
Rhason Cheung had a naive problem, and asked Teacher Mai for help. But Teacher Mai thought this problem was too simple, sometimes naive. So she ask you for help.
She has a tree with n vertices, numbered from 1 to n. The weight of i-th node is wi.
You need to support two kinds of operations: modification and query.
For a modification operation u,w, you need to change the weight of u-th node into w.
For a query operation u,v, you should output ∑ni=1∑nj=1f(i,j). If there is a vertex on the path from u to v and the path from i to j in the tree, f(i,j)=wiwj, otherwise f(i,j)=0. The number can be large, so print the number modulo 109+7
She has a tree with n vertices, numbered from 1 to n. The weight of i-th node is wi.
You need to support two kinds of operations: modification and query.
For a modification operation u,w, you need to change the weight of u-th node into w.
For a query operation u,v, you should output ∑ni=1∑nj=1f(i,j). If there is a vertex on the path from u to v and the path from i to j in the tree, f(i,j)=wiwj, otherwise f(i,j)=0. The number can be large, so print the number modulo 109+7
Input
There are multiple test cases.
For each test case, the first line contains two numbers n,m(1≤n,m≤105).
There are n numbers in the next line, the i-th means wi(0≤wi≤109).
Next n−1 lines contain two numbers each, ui and vi, that means that there is an edge between ui and vi.
The following are m lines. Each line indicates an operation, and the format is "1 u w"(modification) or "2 u v"(query)(0≤w≤109)
For each test case, the first line contains two numbers n,m(1≤n,m≤105).
There are n numbers in the next line, the i-th means wi(0≤wi≤109).
Next n−1 lines contain two numbers each, ui and vi, that means that there is an edge between ui and vi.
The following are m lines. Each line indicates an operation, and the format is "1 u w"(modification) or "2 u v"(query)(0≤w≤109)
Output
For each test case, print the answer for each query operation.
Sample Input
6 5
1 2 3 4 5 6
1 2
1 3
2 4
2 5
4 6
2 3 5
1 5 6
2 2 3
1 1 7
2 2 4
Sample Output
341
348
612
题意:
给你一棵n个节点的树,有点权。
要求支持两种操作:
操作1:更改某个节点的权值。
操作2:给定u,v, 求 Σw[i][j] i , j 为任意两点且i到j的路径与u到v的路径相交。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9; LL aa[N],bb[N],in[N],out[N]; int dep[N],head[N],t=1,sz[N],fa[N],indexS,top[N],pos[N],son[N]; struct ss{int to,next;}e[N*2]; int n; void add(int u,int v) {e[t].to = v;e[t].next = head[u];head[u] = t++;} void dfs(int u) { int k = 0; sz[u] = 1; if(u!=1)dep[u] = dep[fa[u]] + 1; for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(to == fa[u]) continue; fa[to] = u; dfs(to); sz[u] += sz[to]; if(sz[to] > sz[k]) k = to; } if(k) son[u] = k; } void dfs(int u,int chain) { int k = 0; pos[u] = ++indexS; in[u] = indexS; top[u] = chain; if(son[u] > 0) dfs(son[u],chain); for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(dep[to] > dep[u] && son[u] != to) dfs(to,to); } out[u] = indexS; } void update(int x,LL val,LL *sum) { for(int i = x; i < N; i += i&(-i)) { sum[i] += val; sum[i] %= mod; } } LL ask(int x,LL *sum) { LL res = 0; for(int i = x; i; i-=i&(-i)) res += sum[i],res %= mod; return res; } LL allsum,C_tree[N],C_sqtree[N],a[N]; void update(int x,LL val) { int u = top[x]; while(fa[u] > 0) { LL all = ask(out[u],C_tree) - ask(in[u]-1,C_tree); LL newall = (val - a[x])*(val - a[x])%mod + 1LL*2*all*(val-a[x])%mod; update(in[fa[u]],newall%mod,C_sqtree); u = top[fa[u]]; } update(in[x],val-a[x],C_tree); a[x] = val; } LL query(int x,int y) { LL res = 0,hav = 0; while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); res += ask(in[x],C_sqtree) - ask(in[top[x]]-1,C_sqtree); res %= mod; if(son[x]>0) { LL all = ask(out[son[x]],C_tree) - ask(in[son[x]]-1,C_tree); res += all*all; res %= mod; } if(hav>0) { LL all = ask(out[hav],C_tree) - ask(in[hav]-1,C_tree); res -= all * all; res %= mod; } hav = top[x]; x = fa[hav]; } if(dep[x] < dep[y]) swap(x,y); res += ask(in[x],C_sqtree) - ask(in[y]-1,C_sqtree); res %= mod; if(fa[y] > 0) { LL all = ((ask(out[1],C_tree) - ask(out[y],C_tree) + ask(in[y]-1,C_tree))%mod+mod)%mod; res += (all*all)%mod; res %= mod; } if(son[x]>0) { LL all = ask(out[son[x]],C_tree) - ask(in[son[x]]-1,C_tree); res += all*all; res %= mod; } if(hav>0) { LL all = ask(out[hav],C_tree) - ask(in[hav]-1,C_tree); res -= all * all; res %= mod; } return res; } int Q; void init() { memset(head,0,sizeof(head)); t = 1; indexS = 0; allsum = 0; memset(son,-1,sizeof(son)); son[0] = 0; memset(C_tree,0,sizeof(C_tree)); memset(C_sqtree,0,sizeof(C_sqtree)); } int main() { while(scanf("%d%d",&n,&Q)!=EOF) { init(); for(int i = 1; i <= n; ++i) scanf("%I64d",&a[i]); allsum = allsum*allsum%mod; for(int i = 1; i < n; ++i) { int x,y; scanf("%d%d",&x,&y); add(x,y),add(y,x); } fa[1] = -1; dfs(1); dfs(1,1); for(int i = 1; i <= n; ++i) { LL uu = a[i]; a[i] = 0; update(i,uu); } while(Q--) { int op,x; LL y; LL all = ask(out[1],C_tree); scanf("%d%d%I64d",&op,&x,&y); if(op == 1) { update(x,y); } else printf("%I64d\n",((all*all%mod - query(x,y)) % mod + mod)%mod); } } return 0; }