SPOJ 375 Query on a tree(树链剖分)
https://vjudge.net/problem/SPOJ-QTREE
题意:
给出一棵树,树上的每一条边都有权值,现在有查询和更改操作,如果是查询,则要输出u和v之间的最大权值。
思路:
树链剖分的模板题。
树链剖分简单来说,就是把树分成多条链,然后再将这些链映射到数据结构上处理(线段树,树状数组等等)。
具体的话可以看看这个http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 const int INF = 0x3f3f3f3f; 14 const int maxn=20000+5; 15 16 int n; 17 int tot; 18 int pos; 19 int head[maxn]; 20 int dep[maxn]; //节点在树上的深度 21 int top[maxn]; //节点所在重链的顶端节点 22 int num[maxn]; //节点的子节点数 23 int fa[maxn]; //父亲结点 24 int p[maxn]; //节点与其父亲结点在线段树中的位置 25 int fp[maxn]; //和p数组相反 26 int son[maxn]; //节点的重儿子 27 int e[maxn][3]; 28 29 struct node 30 { 31 int v,next; 32 }edge[2*maxn]; 33 34 void addEdge(int u, int v) 35 { 36 edge[tot].v=v; 37 edge[tot].next=head[u]; 38 head[u]=tot++; 39 } 40 41 42 //求出重儿子等等 43 void dfs(int u, int pre, int d) 44 { 45 dep[u]=d; 46 son[u]=-1; 47 num[u]=1; 48 fa[u]=pre; 49 for(int i=head[u];i!=-1;i=edge[i].next) 50 { 51 int v=edge[i].v; 52 if(v==pre) continue; 53 dfs(v,u,d+1); 54 num[u]+=num[v]; 55 if(son[u]==-1 || num[son[u]]<num[v]) //找到子节点最多的作为重儿子 56 son[u]=v; 57 } 58 } 59 60 //处理top值以及在线段树上的位置 61 void getpos(int u, int sp) 62 { 63 top[u]=sp; 64 if(son[u]!=-1) //先处理重儿子 65 { 66 p[u]=pos++; //保证了一条链上的顶点在线段树上连续 67 fp[p[u]]=u; 68 getpos(son[u],sp); 69 } 70 else //到了叶子节点就不再往下处理 71 { 72 p[u]=pos++; 73 fp[p[u]]=u; 74 return; 75 } 76 for(int i=head[u];i!=-1;i=edge[i].next) //处理其他顶点 77 { 78 int v=edge[i].v; 79 if(v==son[u] || v==fa[u]) continue; 80 getpos(v,v); 81 } 82 } 83 84 int val[maxn<<2]; 85 int MAX[maxn<<2]; 86 87 88 void PushUp(int o) 89 { 90 MAX[o]=max(MAX[o<<1],MAX[o<<1|1]); 91 } 92 93 void build(int l, int r, int o) 94 { 95 if(l==r) 96 { 97 MAX[o]=val[l]; 98 return; 99 } 100 int mid=(l+r)>>1; 101 build(l,mid,o<<1); 102 build(mid+1,r,o<<1|1); 103 PushUp(o); 104 } 105 106 void update(int pos, int x, int l, int r, int o) 107 { 108 if(l==r) {MAX[o]=x;return;} 109 int mid=(l+r)>>1; 110 if(pos<=mid) update(pos,x,l,mid,o<<1); 111 else update(pos,x,mid+1,r,o<<1|1); 112 PushUp(o); 113 } 114 115 int query(int ql, int qr, int l, int r, int o) 116 { 117 if(ql<=l && qr>= r) return MAX[o]; 118 int mid=(l+r)>>1; 119 int res=0; 120 if(ql<=mid) res=max(res,query(ql,qr,l,mid,o<<1)); 121 if(qr>mid) res=max(res,query(ql,qr,mid+1,r,o<<1|1)); 122 return res; 123 } 124 125 126 int lca(int x, int y) 127 { 128 int ans=0; 129 while(top[x]!=top[y]) //不在一条链上时 130 { 131 if(dep[top[x]]<dep[top[y]]) swap(x,y); //从深度较深的开始 132 ans=max(ans,query(p[top[x]],p[x],1,n,1)); 133 x=fa[top[x]]; //x所在链的顶点的父节点,转到另一条链上 134 } 135 if(dep[x]>dep[y]) swap(x,y); 136 if(x!=y) ans=max(ans,query(p[son[x]],p[y],1,n,1)); 137 return ans; 138 } 139 140 141 int main() 142 { 143 //freopen("in.txt","r",stdin); 144 int T; 145 scanf("%d",&T); 146 while(T--) 147 { 148 tot=0; 149 memset(head,-1,sizeof(head)); 150 scanf("%d",&n); 151 for(int i=1;i<n;i++) 152 { 153 scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); 154 addEdge(e[i][0],e[i][1]); 155 addEdge(e[i][1],e[i][0]); 156 } 157 dfs(1,0,0); 158 pos=1; 159 getpos(1,1); 160 for(int i=1;i<n;i++) 161 { 162 if(dep[e[i][0]]<dep[e[i][1]]) swap(e[i][0],e[i][1]); 163 val[p[e[i][0]]]=e[i][2]; 164 } 165 build(1,n,1); 166 char s[10]; int u,v; 167 while(scanf("%s",s)) 168 { 169 if(s[0]=='D') break; 170 scanf("%d%d",&u,&v); 171 if(s[0]=='Q') printf("%d\n",lca(u,v)); 172 else update(p[e[u][0]],v,1,n,1); 173 } 174 } 175 return 0; 176 }