https://www.cnblogs.com/violet-acmer/p/9711441.html
题意:
You are given a tree (an acyclic undirected connected graph,无向无环连通图) with N nodes,
and edges numbered 1, 2, 3...N-1.
We will ask you to perform some instructions of the following form:
有两个操作
CHANGE i ti : change the cost of the i-th edge to ti(第i条边的权值变为ti)
or
QUERY a b : ask for the maximum edge cost on the path from node a to node b
(查询节点a,b间路径的最大权值)
题解:
树链剖分模板题,看代码理解的更快;
AC代码献上:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 using namespace std; 6 #define ls(x) ((x)<<1) 7 #define rs(x) ((x)<<1 | 1) 8 const int maxn=10010; 9 10 //===========链式前向星=============== 11 struct Node1 12 { 13 int to; 14 int next; 15 }edge[2*maxn]; 16 int head[maxn]; 17 int cnt; 18 void addEdge(int u,int v) 19 { 20 edge[cnt].to=v; 21 edge[cnt].next=head[u]; 22 head[u]=cnt++; 23 } 24 //==================================== 25 //=========树链剖分用到的变量========= 26 int fa[maxn];//fa[u] : 节点u的父节点 27 int newId[maxn];//newId[u] : u与其父亲节点的连边在线段树中的位置 28 int depth[maxn];//depth[u] : 节点u的深度 29 int siz[maxn];//siz[u] : 以u为根的子树的节点数 30 int top[maxn];//top[u] : 节点u所在的重链的顶端节点 31 int son[maxn];//son[u] : 节点u重儿子 32 int label;//记录newId[]中新边对应的编号 33 //==================================== 34 //==========两次DFS()================ 35 void dfs1(int u,int f,int d) //第一遍dfs求出fa[],depth[],siz[],son[] 36 { 37 depth[u]=d; 38 fa[u]=f; 39 siz[u]=1; 40 for(int i=head[u];~i;i=edge[i].next) 41 { 42 int to=edge[i].to; 43 if(to != f) 44 { 45 dfs1(to,u,d+1); 46 siz[u] += siz[to]; 47 if(son[u] == -1 || siz[to] > siz[son[u]]) 48 son[u] = to; 49 } 50 } 51 } 52 void dfs2(int u,int sp) //第二遍dfs求出top[]和newId[] 53 { 54 top[u]=sp; 55 newId[u]=++label; 56 if(son[u] == -1) 57 return ; 58 dfs2(son[u],sp); 59 60 for(int i=head[u];~i;i=edge[i].next) 61 { 62 int to=edge[i].to; 63 if(to != son[u] && to != fa[u]) 64 dfs2(to,to); 65 } 66 } 67 //=================================== 68 //=============线段树================ 69 struct Node2 70 { 71 int l,r; 72 int Max; 73 int mid() 74 { 75 return l+((r-l)>>1); 76 } 77 }segTree[maxn*4]; 78 void buildTree(int l,int r,int pos) 79 { 80 segTree[pos].l = l,segTree[pos].r = r; 81 segTree[pos].Max = 0; 82 if(l == r) 83 return; 84 85 int mid = (l+r)/2; 86 buildTree(l,mid,ls(pos)); 87 buildTree(mid+1,r,rs(pos)); 88 } 89 void push_up(int k)//向上更新 90 { 91 segTree[k].Max = max(segTree[ls(k)].Max,segTree[rs(k)].Max); 92 } 93 void update(int k,int val,int pos) //单点更新 94 { 95 if(segTree[pos].l == segTree[pos].r) 96 { 97 segTree[pos].Max = val; 98 return; 99 } 100 101 int mid=segTree[pos].mid(); 102 103 if(k <= mid) 104 update(k,val,ls(pos)); 105 else 106 update(k,val,rs(pos)); 107 push_up(pos); 108 } 109 int query(int l,int r,int pos)//查询线段树中[l,r]的最大值 110 { 111 if(segTree[pos].l == l && segTree[pos].r == r) 112 return segTree[pos].Max; 113 114 int mid=segTree[pos].mid(); 115 116 if(r <= mid) 117 return query(l,r,ls(pos)); 118 else if(l > mid) 119 return query(l,r,rs(pos)); 120 else 121 return max(query(l,mid,ls(pos)),query(mid+1,r,rs(pos))); 122 } 123 int Find(int u,int v)//查询u->v边的最大值 124 { 125 int res=0; 126 while(top[u] != top[v]) 127 { 128 if(depth[top[u]] > depth[top[v]]) 129 { 130 res=max(res,query(newId[top[u]],newId[u],1)); 131 u=fa[top[u]]; 132 } 133 else 134 { 135 res=max(res,query(newId[top[v]],newId[v],1)); 136 v=fa[top[v]]; 137 } 138 } 139 if(u == v) 140 return res; 141 if(depth[u] > depth[v]) 142 swap(u,v); 143 return max(res,query(newId[son[u]],newId[v],1)); 144 } 145 //=================================== 146 void Init() 147 { 148 cnt=0; 149 memset(head,-1,sizeof(head)); 150 label=0; 151 memset(son,-1,sizeof(son)); 152 } 153 int e[maxn][3]; 154 int main() 155 { 156 int T; 157 scanf("%d",&T); 158 while(T--) 159 { 160 int n; 161 Init(); 162 scanf("%d",&n); 163 for(int i=1;i < n;++i) 164 { 165 scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); 166 addEdge(e[i][0],e[i][1]); 167 addEdge(e[i][1],e[i][0]); 168 } 169 dfs1(1,0,0); 170 dfs2(1,1); 171 buildTree(1,label,1); 172 for(int i=1;i < n;++i) 173 { 174 if(depth[e[i][0]] > depth[e[i][1]]) 175 swap(e[i][0],e[i][1]);//确保 e[i][0] 为 e[i][1]的父节点 176 update(newId[e[i][1]],e[i][2],1);//更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置 177 } 178 char op[10]; 179 while(scanf("%s",op) && op[0] != 'D') 180 { 181 int u,v; 182 scanf("%d%d",&u,&v); 183 if(op[0] == 'Q') 184 printf("%d ",Find(u,v)); 185 else 186 update(newId[e[u][1]],v,1); 187 } 188 } 189 }
分割线:2019.5.10
省赛倒计时2天;
熟悉一下树链剖分,改改代码风格:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ls(x) (x<<1) 4 #define rs(x) (x<<1|1) 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 const int maxn=1e4+50; 7 8 int n;///n个节点 9 int e[maxn][3];///节点e[i][0]与节点e[i][1]有条权值为e[i][2]的边 10 int num; 11 int head[maxn]; 12 struct Edge 13 { 14 int to; 15 int next; 16 }G[maxn<<1]; 17 void addEdge(int u,int v) 18 { 19 G[num]=Edge{v,head[u]}; 20 head[u]=num++; 21 } 22 int fa[maxn];///fa[u]:节点u的父节点 23 int tid[maxn];///tid[u]:节点u在线段树中的新编号 24 int rid[maxn];///tid[u]=cnt,rid[cnt]=u,通过线段树中的编号查找节点 25 int dep[maxn];///节点的深度 26 int siz[maxn];///siz[u]:以u为根的子树的节点数 27 int son[maxn];///son[u]:节点u重儿子 28 int top[maxn];///top[u]:节点u所在重链的顶端节点 29 struct Seg 30 { 31 int l,r; 32 int maxVal;///区间维护最大值,根据题意而定 33 int mid(){return l+((r-l)>>1);} 34 int len(){return r-l+1;} 35 }seg[maxn<<2]; 36 void pushUp(int pos) 37 { 38 seg[pos].maxVal=max(seg[ls(pos)].maxVal,seg[rs(pos)].maxVal); 39 } 40 void buildSegTree(int l,int r,int pos) 41 { 42 seg[pos].l=l; 43 seg[pos].r=r; 44 seg[pos].maxVal=0; 45 if(l == r) 46 return ; 47 int mid=l+((r-l)>>1); 48 buildSegTree(l,mid,ls(pos)); 49 buildSegTree(mid+1,r,rs(pos)); 50 } 51 void Update(int l,int val,int pos)///单点更新 52 { 53 if(seg[pos].l == seg[pos].r) 54 { 55 seg[pos].maxVal=val; 56 return ; 57 } 58 int mid=seg[pos].mid(); 59 if(l <= mid) 60 Update(l,val,ls(pos)); 61 else 62 Update(l,val,rs(pos)); 63 pushUp(pos); 64 } 65 int Query(int l,int r,int pos)///区间查询 66 { 67 if(seg[pos].l == l && seg[pos].r == r) 68 return seg[pos].maxVal; 69 int mid=seg[pos].mid(); 70 if(r <= mid) 71 return Query(l,r,ls(pos)); 72 else if(l > mid) 73 return Query(l,r,rs(pos)); 74 else 75 return max(Query(l,mid,ls(pos)),Query(mid+1,r,rs(pos))); 76 } 77 int Find(int u,int v) 78 { 79 int topU=top[u]; 80 int topV=top[v]; 81 int ans=0; 82 while(topU != topV)///u,v不在一条重链上 83 { 84 if(dep[topU] > dep[topV])///人为规定topU的深度低 85 { 86 swap(topU,topV); 87 swap(u,v); 88 } 89 ans=max(ans,Query(tid[topV],tid[v],1)); 90 v=fa[topV];///v来到topV的父节点所在的重链 91 topV=top[v]; 92 } 93 if(u == v) 94 return ans; 95 96 if(dep[u] > dep[v]) 97 swap(u,v); 98 return max(ans,Query(tid[son[u]],tid[v],1)); 99 } 100 void DFS1(int u,int f,int depth)///第一遍DFS求出fa,dep,siz,son 101 { 102 fa[u]=f; 103 siz[u]=1; 104 dep[u]=depth; 105 for(int i=head[u];~i;i=G[i].next) 106 { 107 int v=G[i].to; 108 if(v == f)///此处是v == f才continue,在这儿出过错 109 continue; 110 DFS1(v,u,depth+1); 111 siz[u] += siz[v]; 112 if(son[u] == -1 || siz[v] > siz[son[u]])///更新重儿子 113 son[u]=v; 114 } 115 } 116 void DFS2(int u,int anc,int &k)///第二遍DFS求出tid,rid,top 117 { 118 top[u]=anc; 119 tid[u]=++k; 120 rid[k]=u; 121 if(son[u] == -1) 122 return ; 123 DFS2(son[u],anc,k); 124 125 for(int i=head[u];~i;i=G[i].next) 126 { 127 int v=G[i].to; 128 if(v != son[u] && v != fa[u]) 129 DFS2(v,v,k); 130 } 131 } 132 void Solve() 133 { 134 DFS1(1,0,0); 135 int k=0; 136 DFS2(1,1,k); 137 buildSegTree(1,k,1);///[1,k]重新编号的节点建树 138 139 for(int i=1;i < n;++i) 140 { 141 ///将e[i][0]与e[i][1]的边权存入儿子节点e[i][1]中 142 if(dep[e[i][0]] > dep[e[i][1]]) 143 swap(e[i][0],e[i][1]); 144 ///更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置 145 Update(tid[e[i][1]],e[i][2],1); 146 } 147 char order[10]; 148 while(~scanf("%s",order) && order[0] != 'D') 149 { 150 int u,v; 151 scanf("%d%d",&u,&v); 152 if(order[0] == 'Q') 153 printf("%d ",Find(u,v));///查询节点u,v间路径的最大值 154 else///更新第u条边的权值,变为v,第u条边的权值信息记录在了tid[e[u][1]]中 155 Update(tid[e[u][1]],v,1); 156 } 157 } 158 159 void Init()///初始化head,num,son 160 { 161 num=0; 162 mem(head,-1); 163 mem(son,-1); 164 } 165 int main() 166 { 167 int test; 168 while(~scanf("%d",&test)) 169 { 170 while(test--) 171 { 172 Init();///多组输入test,Init()放在while(test--)内 173 scanf("%d",&n); 174 for(int i=1;i < n;++i)///n-1条边 175 { 176 int u,v,w; 177 scanf("%d%d%d",&u,&v,&w); 178 e[i][0]=u; 179 e[i][1]=v; 180 e[i][2]=w; 181 addEdge(u,v); 182 addEdge(v,u); 183 } 184 Solve(); 185 } 186 } 187 return 0; 188 }