模板 — 树链剖分
Contents
树链剖分
题目描述
一棵树有n个节点,每个节点有一个点权ai,共有m个操作:
|
操作编号
|
操作格式
|
说明
|
|
1.更新
|
UPDATE p x
|
把点p的权值修改为x
|
|
2.查询最大
|
MAX p q
|
查询p到q路径中最大点权
|
|
3.查询和
|
SUM p q
|
查询p到q路径中点权和
|
输入
第一行两个整数n和m;
接下来一行中n个整数表示初始点权;
接下来行中每行两个整数p和q,表示p和q之间有一条边相连;
接下来m行每行一个操作如上表所示。
输出
对于每一个查询操作,输出一行包含一个整数为对应的答案。
样例输入
4 3
3 6 8 5
1 2
1 3
2 4
MAX 1 4
UPDATE 1 5
SUM 1 3
样例输出
6
13
提示

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100010
inline int max(int a,int b){return a>b?a:b;}
void swap(int &a,int &b){int c=a^b;b=b^c;a=a^c;}
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct qaz{int fro,to;}e[N<<1];
int tot[N],siz[N],top[N],son[N],dep[N],fa[N],tid[N],tim,rrank[N],lj[N],cnt;
void add(int a,int b){e[++cnt].fro=lj[a];e[cnt].to=b;lj[a]=cnt;}
void dfs1(int u,int father,int d)
{
dep[u]=d;
fa[u]=father;
siz[u]=1;
for(int i=lj[u];i;i=e[i].fro)
{
int v=e[i].to;
if(v!=father)
{
dfs1(v,u,d+1); siz[u]+=siz[v];
if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
tid[u]=++tim;
rrank[tim]=u;
if(son[u]==-1) return;
dfs2(son[u],tp);
for(int i=lj[u];i;i=e[i].fro)
{
int v=e[i].to;
if(son[u]!=v&&v!=fa[u]) dfs2(v,v);
}
}
int n,m,p,q,a[N];
char ss;
struct tree{int l,r,maxx,sum;}tr[N<<2];
void pu(int x)
{
tr[x].maxx=max(tr[x<<1].maxx,tr[x<<1|1].maxx);
tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
}
void build(int l,int r,int x)
{
tr[x].l=l;tr[x].r=r;
if(l==r)
{
tr[x].maxx=a[rrank[l]];
tr[x].sum=a[rrank[l]];
return;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);build(mid+1,r,x<<1|1);
pu(x);
}
void xg(int c,int k,int x)
{
if(tr[x].l==tr[x].r)
{
tr[x].sum=tr[x].maxx=k;
return;
}
int mid=(tr[x].l+tr[x].r)>>1;
if(c<=mid) xg(c,k,x<<1);
else xg(c,k,x<<1|1);
pu(x);
}
inline int fdmax(int l,int r,int x)
{
if(tr[x].l==l&&tr[x].r==r) return tr[x].maxx;
int mid=(tr[x].l+tr[x].r)>>1;
if(r<=mid) return fdmax(l,r,x<<1);
else if(l>mid) return fdmax(l,r,x<<1|1);
else return max(fdmax(l,mid,x<<1),fdmax(mid+1,r,x<<1|1));
}
inline int fdsum(int l,int r,int x)
{
if(tr[x].l==l&&tr[x].r==r) return tr[x].sum;
int mid=(tr[x].l+tr[x].r)>>1;
if(r<=mid) return fdsum(l,r,x<<1);
else if(l>mid) return fdsum(l,r,x<<1|1);
else return fdsum(l,mid,x<<1)+fdsum(mid+1,r,x<<1|1);
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++)
{
p=read();q=read();
add(p,q);add(q,p);
}
for(int i=0;i<=n;i++) son[i]=-1;
dfs1(1,0,0);
dfs2(1,1);
build(1,n,1);
for(int i=0;i<m;i++)
{
ss=' ';
while(ss<'A'||ss>'Z') ss=getchar();
p=read();q=read();
int tmp=0;
if(ss=='U') xg(tid[p],q,1);
else if(ss=='M')
{
while(top[p]!=top[q])
{
if(dep[top[p]]<dep[top[q]]) swap(p,q);
tmp=max(tmp,fdmax(tid[top[p]],tid[p],1));
p=fa[top[p]];
}
if(dep[p]>dep[q]) swap(p,q);
tmp=max(tmp,fdmax(tid[p],tid[q],1));
}
else if(ss=='S')
{
while(top[p]!=top[q])
{
if(dep[top[p]]<dep[top[q]]) swap(p,q);
tmp+=fdsum(tid[top[p]],tid[p],1);
p=fa[top[p]];
}
if(dep[p]>dep[q]) swap(p,q);
tmp+=fdsum(tid[p],tid[q],1);
}
if(ss!='U')printf("%d\n",tmp);
}
return 0;
}
发表评论