题目地址:http :// www . lydsy . com / JudgeOnline / problem . php ? id = 1036
题目大意:给出一棵树,每个点有一个权值,要求三种操作:1.修改某个点的权值,2.询问x到y路径上各点的权值最大值,3.询问x到y路径上各点的权值之和。
算法讨论:树链剖分模板题。
Code:
#include <cstdio> #include <algorithm> #define N 30000 #define oo 0x7f7f7f7f using namespace std; int n,x,y,tot,q,mm,w[N+10],next[N*2+10],son[N+10],ed[N*2+10],fa[N+10],deep[N+10],size[N+10],heavy[N+10],tree1[N*4+10],tree2[N*4+10],head[N+10],id[N+10],num[N+10]; bool vis[N+10]; char s[10]; void add(int x,int y){ next[++mm]=son[x]; son[x]=mm; ed[mm]=y; } void dfs1(int x){ vis[x]=1; size[x]=1; for (int i=son[x];i;i=next[i]){ int y=ed[i]; if (!vis[y]){ fa[y]=x; deep[y]=deep[x]+1; dfs1(y); size[x]+=size[y]; if (size[y]>size[heavy[x]]) heavy[x]=y; } } } void dfs2(int x){ vis[x]=1; id[x]=++tot; num[tot]=x; if (!head[x]) head[x]=x; if (heavy[x]) head[heavy[x]]=head[x],dfs2(heavy[x]); for (int i=son[x];i;i=next[i]){ int y=ed[i]; if (!vis[y]) dfs2(y); } } void up(int k){ tree1[k]=max(tree1[k*2],tree1[k*2+1]); tree2[k]=tree2[k*2]+tree2[k*2+1]; } void build(int k,int lc,int rc){ if (lc==rc){ tree1[k]=tree2[k]=w[num[lc]]; return; } int mid=(lc+rc)/2; build(k*2,lc,mid); build(k*2+1,mid+1,rc); up(k); } void change(int k,int lc,int rc,int x,int y){ if (lc==rc){ tree1[k]=tree2[k]=y; return; } int mid=(lc+rc)/2; if (x<=mid) change(k*2,lc,mid,x,y); else change(k*2+1,mid+1,rc,x,y); up(k); } int query1(int k,int lc,int rc,int l,int r){ if (l==lc && r==rc) return tree1[k]; int mid=(lc+rc)/2; if (r<=mid) return query1(k*2,lc,mid,l,r); if (l>mid) return query1(k*2+1,mid+1,rc,l,r); return max(query1(k*2,lc,mid,l,mid),query1(k*2+1,mid+1,rc,mid+1,r)); } int query2(int k,int lc,int rc,int l,int r){ if (l==lc && r==rc) return tree2[k]; int mid=(lc+rc)/2; if (r<=mid) return query2(k*2,lc,mid,l,r); if (l>mid) return query2(k*2+1,mid+1,rc,l,r); return query2(k*2,lc,mid,l,mid)+query2(k*2+1,mid+1,rc,mid+1,r); } int qmax(int x,int y){ int ans=-oo; while (head[x]!=head[y]){ if (deep[head[x]]<deep[head[y]]) swap(x,y); ans=max(ans,query1(1,1,tot,id[head[x]],id[x])); x=fa[head[x]]; } if (deep[x]>deep[y]) swap(x,y); ans=max(ans,query1(1,1,tot,id[x],id[y])); return ans; } int qsum(int x,int y){ int ans=0; while (head[x]!=head[y]){ if (deep[head[x]]<deep[head[y]]) swap(x,y); ans+=query2(1,1,tot,id[head[x]],id[x]); x=fa[head[x]]; } if (deep[x]>deep[y]) swap(x,y); ans+=query2(1,1,tot,id[x],id[y]); return ans; } int main(){ scanf("%d",&n); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } for (int i=1;i<=n;++i) scanf("%d",&w[i]); dfs1(1); for (int i=1;i<=n;++i) vis[i]=0; dfs2(1); build(1,1,tot); scanf("%d",&q); for (int i=1;i<=q;++i){ scanf("%s%d%d",s,&x,&y); if (s[0]==‘C‘) change(1,1,tot,id[x],y); else if (s[0]==‘Q‘ && s[1]==‘M‘) printf("%d\n",qmax(x,y)); else printf("%d\n",qsum(x,y)); } return 0; }
By Charlie Pan
Mar 12,2014
BZOJ 1036: [ZJOI2008]树的统计Count,布布扣,bubuko.com
BZOJ 1036: [ZJOI2008]树的统计Count
原文地址:http://blog.csdn.net/charlie_pyc/article/details/25652453