洛谷 P2590 [ZJOI2008]树的统计(线段树,树链剖分)
传送门
解题思路
关于两点之间的最短距离的区间操作,很显然是树链剖分。
因为既有区间和还有区间最大值,所以我们建立两个线段树。
然后就是树剖的常规操作了。
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 #include<iomanip> 7 using namespace std; 8 const int maxn=100005; 9 int n,q,v[maxn],cnt,dep[maxn],siz[maxn],tp[maxn],son[maxn],f[maxn]; 10 int s1[maxn*4],s2[maxn*4],p[maxn]; 11 int id[maxn],rk[maxn]; 12 struct Edge{ 13 int v,next; 14 }e[maxn]; 15 void insert(int u,int v){ 16 cnt++; 17 e[cnt].v=v; 18 e[cnt].next=p[u]; 19 p[u]=cnt; 20 } 21 void dfs1(int fa,int u,int deep){ 22 f[u]=fa; 23 dep[u]=deep; 24 siz[u]=1; 25 for(int i=p[u];i!=-1;i=e[i].next){ 26 if(e[i].v==fa) continue; 27 dfs1(u,e[i].v,deep+1); 28 siz[u]+=siz[e[i].v]; 29 if(siz[e[i].v]>siz[son[u]]) son[u]=e[i].v; 30 } 31 } 32 void dfs2(int fa,int u,int top){ 33 tp[u]=top; 34 cnt++; 35 id[u]=cnt; 36 rk[cnt]=u; 37 if(!son[u]) return; 38 dfs2(u,son[u],top); 39 for(int i=p[u];i!=-1;i=e[i].next){ 40 if(e[i].v==son[u]||e[i].v==fa) continue; 41 dfs2(u,e[i].v,e[i].v); 42 } 43 } 44 void build(int id,int l,int r){ 45 if(l==r){ 46 s1[id]=s2[id]=v[rk[l]]; 47 return; 48 } 49 int mid=(l+r)/2; 50 build(id*2,l,mid); 51 build(id*2+1,mid+1,r); 52 s1[id]=s1[id*2]+s1[id*2+1]; 53 s2[id]=max(s2[id*2],s2[id*2+1]); 54 } 55 void add(int id,int x,int l,int r,int value){ 56 if(l==r){ 57 s1[id]=value; 58 s2[id]=value; 59 return; 60 } 61 int mid=(l+r)/2; 62 if(x<=mid) add(id*2,x,l,mid,value); 63 if(x>mid) add(id*2+1,x,mid+1,r,value); 64 s1[id]=s1[id*2]+s1[id*2+1]; 65 s2[id]=max(s2[id*2],s2[id*2+1]); 66 } 67 int querymax(int id,int x,int y,int l,int r){ 68 if(x<=l&&r<=y) return s2[id]; 69 int mid=(l+r)/2; 70 int res=-9999999; 71 if(x<=mid) res=max(res,querymax(id*2,x,y,l,mid)); 72 if(mid<y) res=max(res,querymax(id*2+1,x,y,mid+1,r)); 73 return res; 74 } 75 int querysum(int id,int x,int y,int l,int r){ 76 if(x<=l&&r<=y) return s1[id]; 77 int mid=(l+r)/2; 78 int res=0; 79 if(x<=mid) res+=querysum(id*2,x,y,l,mid); 80 if(mid<y) res+=querysum(id*2+1,x,y,mid+1,r); 81 return res; 82 } 83 int main() 84 { 85 memset(p,-1,sizeof(p)); 86 cin>>n; 87 for(int i=1;i<n;i++){ 88 int a,b; 89 cin>>a>>b; 90 insert(a,b); 91 insert(b,a); 92 } 93 for(int i=1;i<=n;i++) cin>>v[i]; 94 dfs1(-1,1,1); 95 cnt=0; 96 dfs2(-1,1,1); 97 build(1,1,n); 98 cin>>q; 99 for(int i=1;i<=q;i++){ 100 string s; 101 int a,b; 102 cin>>s>>a>>b; 103 if(s=="CHANGE"){ 104 add(1,id[a],1,n,b); 105 }else{ 106 if(s=="QSUM"){ 107 int ans=0; 108 while(tp[a]!=tp[b]){ 109 if(dep[tp[a]]<dep[tp[b]]) swap(a,b); 110 ans+=querysum(1,id[tp[a]],id[a],1,n); 111 a=f[tp[a]]; 112 } 113 if(dep[a]<dep[b]) swap(a,b); 114 ans+=querysum(1,id[b],id[a],1,n); 115 cout<<ans<<endl; 116 }else{ 117 int ans=-9999999; 118 while(tp[a]!=tp[b]){ 119 if(dep[tp[a]]<dep[tp[b]]) swap(a,b); 120 ans=max(ans,querymax(1,id[tp[a]],id[a],1,n)); 121 a=f[tp[a]]; 122 } 123 if(dep[a]<dep[b]) swap(a,b); 124 ans=max(ans,querymax(1,id[b],id[a],1,n)); 125 cout<<ans<<endl; 126 } 127 } 128 } 129 return 0; 130 }