我终于码了树链剖分,别人半年前学会的东西我终于入门辣!!!
先放全代码:

1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #include<cmath>
5 #define MAXN 30010
6 using namespace std;
7 const int INF=(1<<30);
8 struct rr{
9 int nt,to;
10 }bl[MAXN<<1];int hd[MAXN],itot;
11 void addedge(int x,int y){
12 bl[++itot]=(rr){hd[x],y};
13 hd[x]=itot;
14 return ;
15 }
16 int n;
17 int w[MAXN];
18 int son[MAXN],L[MAXN],top[MAXN],sz[MAXN];
19 int fat[MAXN];
20 int sd[MAXN];
21 int num=0;
22 int line[MAXN];//dfs序上的某一个位置具体是哪个节点
23 void dfs1(int u,int fa){
24 sz[u]=1;fat[u]=fa;
25 for(int i=hd[u],y;i;i=bl[i].nt)
26 if(bl[i].to!=fa){
27 y=bl[i].to;
28 dfs1(y,u);
29 sz[u]+=sz[y];
30 if(sz[son[u]]<sz[y])son[u]=y;
31 }
32 return ;
33 }
34 void dfs2(int u,int fa,int dep){
35 sd[u]=dep;
36 L[u]=++num;line[num]=u;
37 top[u]=(son[fa]==u)?top[fa]:u;
38 if(son[u])dfs2(son[u],u,dep+1);
39 for(int i=hd[u],y;i;i=bl[i].nt)
40 if(bl[i].to!=fa&&bl[i].to!=son[u])dfs2(bl[i].to,u,dep+1);
41 return ;
42 }
43 struct SEGTREE{
44 int mx[MAXN*4],sm[MAXN*4];
45 #define ls (u<<1)
46 #define rs (u<<1|1)
47 void up(int u){
48 mx[u]=max(mx[ls],mx[rs]);
49 sm[u]=sm[ls]+sm[rs];
50 return ;
51 }
52 void build(int u,int l,int r){
53 if(l==r){sm[u]=mx[u]=w[line[l]];return ; }
54 int mid=l+r>>1;
55 build(ls,l,mid),build(rs,mid+1,r);
56 up(u);
57 return ;
58 }
59 void upd(int u,int l,int r,int pos,int val){
60 if(l==r){mx[u]=sm[u]=val;return ; }
61 int mid=l+r>>1;
62 if(pos<=mid)upd(ls,l,mid,pos,val);
63 else upd(rs,mid+1,r,pos,val);
64 up(u);
65 return ;
66 }
67 int qwsm(int u,int l,int r,int x,int y){
68 if(l>=x&&r<=y)return sm[u];
69 int mid=l+r>>1;
70 int res=0;
71 if(mid>=x)res+=qwsm(ls,l,mid,x,y);
72 if(mid+1<=y)res+=qwsm(rs,mid+1,r,x,y);
73 return res;
74 }
75 int qwmx(int u,int l,int r,int x,int y){
76 if(l>=x&&r<=y)return mx[u];
77 int mid=l+r>>1;
78 int res=-INF;
79 if(mid>=x)res=max(res,qwmx(ls,l,mid,x,y));
80 if(mid+1<=y)res=max(res,qwmx(rs,mid+1,r,x,y));
81 return res;
82 }
83 }T;
84 int q;
85 int gtmx(int x,int y){
86 int res=-INF;
87 while(top[x]!=top[y]){
88 if(sd[top[x]]<sd[top[y]])swap(x,y);
89 res=max(res,T.qwmx(1,1,num,L[top[x]],L[x]));
90 x=fat[top[x]];
91 }
92 if(sd[x]<sd[y])swap(x,y);
93 res=max(res,T.qwmx(1,1,num,L[y],L[x]));
94 return res;
95 }
96 int gtsm(int x,int y){
97 int res=0;
98 while(top[x]!=top[y]){
99 if(sd[top[x]]<sd[top[y]])swap(x,y);
100 res+=T.qwsm(1,1,num,L[top[x]],L[x]);
101 x=fat[top[x]];
102 }
103 if(sd[x]<sd[y])swap(x,y);
104 res+=T.qwsm(1,1,num,L[y],L[x]);
105 return res;
106 }
107 int main(){
108 //freopen("count1.in","r",stdin);
109 //freopen("hh.out","w",stdout);
110 scanf("%d",&n);
111 for(int i=1,a,b;i<n;++i){
112 scanf("%d%d",&a,&b);
113 addedge(a,b);addedge(b,a);
114 }
115 for(int i=1;i<=n;++i)scanf("%d",&w[i]);
116 dfs1(1,0);dfs2(1,0,1);
117 T.build(1,1,num);
118 scanf("%d",&q);
119 char opt[17];
120 int u,v;
121 while(q--){
122 scanf("%s%d%d",opt,&u,&v);
123 if(opt[0]=='C')T.upd(1,1,num,L[u],v);
124 else if(opt[1]=='M')printf("%d\n",gtmx(u,v));
125 else printf("%d\n",gtsm(u,v));
126 }
127 return 0;
128 }
着重解释几个代码片:
需要维护的变量:
1 int son[MAXN];//重儿子 2 int L[MAXN];//dfs序中的位置 3 int top[MAXN];//所在重链的链顶 4 int sz[MAXN];//子树的大小 5 int fat[MAXN]; 6 int sd[MAXN];//深度 7 int num=0; 8 int line[MAXN];//dfs序上的某一个位置具体是哪个节点
$dfs1$:
1 void dfs1(int u,int fa){
2 sz[u]=1;fat[u]=fa;
3 for(int i=hd[u],y;i;i=bl[i].nt)
4 if(bl[i].to!=fa){
5 y=bl[i].to;
6 dfs1(y,u);
7 sz[u]+=sz[y];
8 if(sz[son[u]]<sz[y])son[u]=y;//更新重儿子
9 }
10 return ;
11 }
$dfs2$:
1 void dfs2(int u,int fa,int dep){
2 sd[u]=dep;
3 L[u]=++num;line[num]=u;
4 top[u]=(son[fa]==u)?top[fa]:u;
5 //判断是否为链断
6 if(son[u])dfs2(son[u],u,dep+1);
7 //先dfs重儿子,确保一条重链的点在dfs序上是连续的
8 for(int i=hd[u],y;i;i=bl[i].nt)
9 if(bl[i].to!=fa&&bl[i].to!=son[u])dfs2(bl[i].to,u,dep+1);
10 return ;
11 }
建线段树就不说什么了
以询问两点路径最大值为例
$qwmx$:
1 int gtmx(int x,int y){
2 int res=-INF;
3 while(top[x]!=top[y]){
4 if(sd[top[x]]<sd[top[y]])swap(x,y);
5 res=max(res,T.qwmx(1,1,num,L[top[x]],L[x]));
6 x=fat[top[x]];
7 }
8 if(sd[x]<sd[y])swap(x,y);
9 res=max(res,T.qwmx(1,1,num,L[y],L[x]));
10 return res;
11 }
例题:
先咕着,并没有做过几道题。。。
