树链剖分
题目描述
一棵树有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 ",tmp); } return 0; }