树链剖分模板
- 区间,边权
描述
松鼠爸爸为了让松鼠宝宝更熟悉地熟悉采松果的流程,为其定制了一颗“树”,树上有n个点,n-1条边(无环),每条边上都有一定数量的松果。松鼠爸爸为了让松鼠宝宝得到更多的松果,有m次操作,每次操作给定两个点x,y和一个add,在x点到y点的简单路径上所有的边都增加add个松果。然后松鼠宝宝会去采集q次松果(每次采集后边上的松果数量不会减少),q次采集会给定x,y两个点,采集x点到y点路径上的边上的所有松果,现询问q次采集每次采集会获得多少松果。
输入描述:
第一行读入三个数n,m,q(分别代表树上的点数,操作次数,询问次数)
接下来n-1行读入x,y, z(代表x点和y点之间有边且有z个松果)
接下来m行读入x,y,z(分别代表x点,y点,和增加的松果数量)
n <=1e5
m <=1e5
q <=1e5
1 <= x, y <= n
0 <= z <= 1e5
输出描述:
输出q行代表每次采集所采集到的松果的数量和
输入
复制7 3 3 1 2 1 1 3 2 2 4 1 2 5 2 3 6 1 3 7 2 2 3 1 1 2 1 2 3 0 2 3 4 7 1 1
输出
复制6 9 0
#include<bits/stdc++.h> #define int long long const int N = 1e6 + 10; using namespace std; int cnt,fst[N],nxt[N],to[N],w[N<<1],fr[N<<1]; int n,a[N],t[N<<2],tag[N<<2],cov[N<<2]; int siz[N],son[N],dfn[N],Index,top[N],rk[N],dep[N],faz[N]; struct now{ int xx; int dd; }; vector<now>e[N]; map<pair< int , int >, int >mp; void Dfs1( int u, int f) { siz[u]=1; son[u]=0; for ( auto v:e[u]) { if (v.xx==f) continue ; faz[v.xx]=u; dep[v.xx]=dep[u]+1; rk[v.xx]=v.dd; Dfs1(v.xx,u); siz[u]+=siz[v.xx]; if (siz[son[u]]<siz[v.xx]) son[u]=v.xx; } } void Dfs2( int u, int rt) { dfn[u]=++Index; top[u]=rt; a[Index]=mp[{faz[u],u}]; // a[Index] = rk[u]; if (son[u]) Dfs2(son[u],rt); for ( auto v:e[u]) { if (v.xx==faz[u]||v.xx==son[u]) continue ; Dfs2(v.xx,v.xx); } } void PushUp( int rt) { t[rt]=t[rt<<1]+t[rt<<1|1]; } void PushDown( int rt, int l, int r) { int mid = l + r >> 1; t[rt<<1]+=tag[rt] * (mid - l + 1); t[rt<<1|1]+=tag[rt] * (r - mid); tag[rt<<1]+=tag[rt]; tag[rt<<1|1]+=tag[rt]; tag[rt]=0; } void BuildSegmentTree( int rt, int l, int r) { if (l==r) { t[rt]=a[l]; return ; } int mid=l+r>>1; BuildSegmentTree(rt<<1,l,mid); BuildSegmentTree(rt<<1|1,mid+1,r); PushUp(rt); } void ModifyAdd( int rt, int l, int r, int tl, int tr, int val) { if (tl<=l && r<=tr) { t[rt]+=val * (r - l + 1); tag[rt]+=val; return ; } PushDown(rt, l, r); int mid=l+r>>1; if (tl<=mid) ModifyAdd(rt<<1,l,mid,tl,tr,val); if (tr>mid) ModifyAdd(rt<<1|1,mid+1,r,tl,tr,val); PushUp(rt); } int Query( int rt, int l, int r, int tl, int tr) { if (tl<=l && r<=tr) return t[rt]; PushDown(rt, l, r); int mid=l+r>>1,res=0; if (tl<=mid) res+=Query(rt<<1,l,mid,tl,tr); if (tr>mid) res+=Query(rt<<1|1,mid+1,r,tl,tr); return res; } void ModifyAddOnTree( int u, int v, int val) { while (top[u]!=top[v]) { if (dep[top[u]]<dep[top[v]]) swap(u,v); ModifyAdd(1,1,n,dfn[top[u]],dfn[u],val); u=faz[top[u]]; } if (dep[u]>dep[v]) swap(u,v); ModifyAdd(1,1,n,dfn[u]+1,dfn[v],val); } int QueryMaxnOnTree( int u, int v) { int res=0; while (top[u]!=top[v]) { if (dep[top[u]]<dep[top[v]]) swap(u,v); res+=Query(1,1,n,dfn[top[u]],dfn[u]); u=faz[top[u]]; } if (dep[u]>dep[v]) swap(u,v); res+=Query(1,1,n,dfn[u]+1,dfn[v]); return res; } int m, k; signed main() { scanf ( "%lld %lld %lld" ,&n, &m, &k); for ( int i=1;i<n;i++) { int x,y,z; scanf ( "%lld %lld %lld" ,&x,&y,&z); e[x].push_back({y,z}); e[y].push_back({x,z}); mp[{x,y}] = z; mp[{y,x}] = z; } mp[{1,0}] = 0; mp[{0,1}] = 0; Dfs1(1,0); Dfs2(1,1); BuildSegmentTree(1,1,n); for ( int i = 0; i < m; i ++ ) { int x,y,z; cin >> x >> y >> z; ModifyAddOnTree(x,y,z); } for ( int i = 0; i < k; i ++ ){ int x, y; cin >> x >> y; printf ( "%lld\n" ,QueryMaxnOnTree(x,y)); } return 0; } |
- 点权
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:
CHANGE u t
,把结点u的权值改为t。QMAX u v
,询问从点u到点v的路径上的节点的最大权值QSUM u v
, 询问从点u到点v的路径上的节点的权值和。注意:从点u到点v的路径上的节点包括u和v本身。
输入格式
输入的第一行为一个整数n,表示节点的个数。接下来n–1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来一行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以CHANGE u t
或者QMAX u v
或者QSUM u v
的形式给出。
保证1≤n≤3×104,0≤q≤2×104,中途操作中保证每个节点的权值w在−3×104到3×104之间。
输出格式
对于每个QMAX
或者QSUM
的操作,每行输出一个整数表示要求输出的结果。
样例输入
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
样例输出
4
1
2
2
10
6
5
6
5
16
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e6 + 10; int n,m,tot; int sz[N],hs[N],fa[N],dep[N],top[N],l1[N],id[N],a[N]; vector< int >e[N]; void dfs1( int u, int f) { sz[u] = 1; hs[u] = -1; fa[u] = f; dep[u] = dep[f] + 1; for ( auto v:e[u]) { if (v == f) continue ; dfs1(v,u); sz[u] += sz[v]; if (sz[v] > sz[hs[u]]) hs[u] = v; } } void dfs2( int u, int t) { top[u] = t; l1[u] = ++tot; id[tot] = u; if (hs[u] != -1) { dfs2(hs[u],t); } for ( auto v:e[u]) { if (v != fa[u] && v != hs[u]) dfs2(v,v); } } struct NOW{ int mx; int sum; }seg[N*4]; void update( int idx) { seg[idx].mx = max(seg[idx*2].mx,seg[idx*2+1].mx); seg[idx].sum = seg[idx*2].sum + seg[idx*2+1].sum; } void build( int idx, int l, int r) { if (l == r) { seg[idx].mx = seg[idx].sum = a[id[l]]; } else { int mid = (l + r)/2; build(idx*2,l,mid); build(idx*2+1,mid+1,r); update(idx); } } void modify( int idx, int l, int r, int pos, int val) { if (l == r) { seg[idx].mx = val; seg[idx].sum = val; } else { int mid = (l + r)/2; if (pos <= mid) modify(idx*2,l,mid,pos,val); else modify(idx*2+1,mid+1,r,pos,val); update(idx); } } int querysum1( int idx, int l, int r, int ql, int qr) { if (l == ql && r == qr) { return seg[idx].sum; } int mid = (l + r)/2; if (qr <= mid) return querysum1(idx*2,l,mid,ql,qr); else if (ql > mid) return querysum1(idx*2+1,mid+1,r,ql,qr); else { return querysum1(idx*2,l,mid,ql,mid) + querysum1(idx*2+1,mid+1,r,mid+1,qr); } } int querymx1( int idx, int l, int r, int ql, int qr) { if (l == ql && r == qr) { return seg[idx].mx; } int mid = (l + r)/2; if (qr <= mid) return querymx1(idx*2,l,mid,ql,qr); else if (ql > mid) return querymx1(idx*2+1,mid+1,r,ql,qr); else { return max(querymx1(idx*2,l,mid,ql,mid) , querymx1(idx*2+1,mid+1,r,mid+1,qr)); } } int querysum( int u, int v) { int ans = 0; while (top[u]!=top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u,v); ans += querysum1(1,1,n,l1[top[u]],l1[u]); u = fa[top[u]]; } if (dep[u] < dep[v]) swap(u,v); ans += querysum1(1,1,n,l1[v],l1[u]); return ans; } int querymx( int u, int v) { int ans = -1e18; while (top[u]!=top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u,v); ans = max(ans,querymx1(1,1,n,l1[top[u]],l1[u])); u = fa[top[u]]; } if (dep[u] < dep[v]) swap(u,v); ans = max(ans,querymx1(1,1,n,l1[v],l1[u])); return ans; } void solve() { cin >> n; for ( int i = 1;i < n;i ++) { int x,y; cin >> x >> y; e[x].push_back(y); e[y].push_back(x); } for ( int i = 1;i <= n;i ++) cin >> a[i]; dfs1(1,0); dfs2(1,1); build(1,1,n); cin >> m; for ( int i = 1;i <= m;i ++) { string s; int x,y; cin >> s; //cout << s << '\n'; cin >> x >> y; if (s == "CHANGE" ) modify(1,1,n,l1[x],y); else if (s == "QMAX" ) cout <<querymx(x,y)<< '\n' ; else cout << querysum(x,y) << '\n' ; } } signed main() { solve(); } |