树链剖分模板
- 区间,边权
描述
松鼠爸爸为了让松鼠宝宝更熟悉地熟悉采松果的流程,为其定制了一颗“树”,树上有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点,和增加的松果数量)
接下来q行读入x,y(分别代表x点,y点)
n <=1e5
m <=1e5
q <=1e5
1 <= x, y <= n
0 <= z <= 1e5
输出描述:
输出q行代表每次采集所采集到的松果的数量和
示例1
输入
复制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();
}

浙公网安备 33010602011771号