1162 - Min Max Roads
题意:给你一棵带权树,查询两点间最大值和最小值。
题解:建立树剖,然后就可以像序列一样查询了。好久没敲树剖板子了,手敲模板熟悉下。
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
const int inf = ~0u>>2;
int root, n;
struct eg{
int v, nex, val;
eg(){}
eg(int _v, int _val, int _nex) { v = _v, val = _val, nex = _nex; }
}edg[N<<3];
int sav[N][3];
int fir[N], ecnt;
void add(int u, int v, int val){
edg[ecnt] = eg(v, val, fir[u]);
fir[u] = ecnt++;
edg[ecnt] = eg(u, val, fir[v]);
fir[v] = ecnt++;
}
int fa[N], dep[N], siz[N], son[N];
int tree[N<<2], treemin[N<<2];
void dfs(int rt){
siz[rt] = 1, son[rt] = 0;
for(int k = fir[rt]; k != -1; k = edg[k].nex){
if(edg[k].v != fa[rt]){
fa[edg[k].v] = rt;
dep[edg[k].v] = dep[rt] + 1;
dfs(edg[k].v);
if(siz[edg[k].v] > siz[son[rt]]) son[rt] = edg[k].v;
siz[rt] += siz[edg[k].v];
}
}
}
int w[N], top[N], cnt; //w[]为到线段树的映射
void dfs2(int rt, int tp){
w[rt] = ++cnt; top[rt] = tp;
if(son[rt]) dfs2(son[rt], top[rt]);
for(int k = fir[rt]; k != -1; k = edg[k].nex){
if(edg[k].v != son[rt] && edg[k].v != fa[rt]){
dfs2(edg[k].v, edg[k].v);
}
}
}
void update(int rt, int l, int r, int pos, int val){
if(l == r){
tree[rt] = val;
treemin[rt] = val;
return;
}
int mid = (l+r) >> 1;
if(pos <= mid) update(rt<<1, l, mid, pos, val);
else update(rt<<1|1, mid+1, r, pos, val);
tree[rt] = max(tree[rt<<1], tree[rt<<1|1]);
treemin[rt] = min(treemin[rt<<1], treemin[rt<<1|1]);
}
void init(){
scanf("%d", &n);
memset(fir, -1, sizeof(fir));
memset(siz, 0, sizeof(siz));
root = (n+1)/2;
fa[root] = cnt = ecnt = dep[root] = 0;
int a, b, c;
for(int i = 1; i < n; ++i){
scanf("%d %d %d%*c", &a, &b, &c);
sav[i][0] = a, sav[i][1] = b, sav[i][2] = c;
add(a, b, c);
}
dfs(root);
dfs2(root, root);
for(int i = 1; i < n; ++i){
if(dep[sav[i][0]] > dep[sav[i][1]]) swap(sav[i][0], sav[i][1]);
update(1, 1, cnt, w[sav[i][1]], sav[i][2]);
}
}
int maxi(int rt, int l, int r, int ql, int qr){
if( ql > r || qr < l) return 0;
if(ql <= l && qr >= r) return tree[rt];
int mid = (l+r) >> 1;
return max(maxi(rt<<1, l, mid, ql, qr), maxi(rt<<1|1, mid+1, r, ql, qr));
}
int mini(int rt, int l, int r, int ql, int qr){
if(ql > r || qr < l) return inf;
if(ql <= l && qr >= r) return treemin[rt];
int mid = (l+r) >> 1;
return min(mini(rt<<1, l, mid, ql, qr), mini(rt<<1|1, mid+1, r, ql, qr));
}
pair<int,int> solve(int va, int vb){
int f1 = top[va], f2 = top[vb], mx = 0, mi = inf;
while(f1 != f2){
if(dep[f1] < dep[f2]){
swap(f1, f2);
swap(va, vb);
}
mx = max(mx, maxi(1, 1, cnt, w[f1], w[va]));
mi = min(mi, mini(1, 1, cnt, w[f1], w[va]));
va = fa[f1], f1 = top[va];
}
if(va == vb) return make_pair(mi, mx);
if(dep[va] > dep[vb]) swap(va, vb);
mx = max(mx, maxi(1, 1, cnt, w[son[va]], w[vb]));
mi = min(mi, mini(1, 1, cnt, w[son[va]], w[vb]));
return make_pair(mi, mx);
}
int main(){
int T, ca = 1;
scanf("%d", &T);
while(T--){
init();
int q;
scanf("%d", &q);
printf("Case %d:\n", ca++);
while(q--){
int a, b;
scanf("%d%d", &a, &b);
pair<int, int> ans = solve(a, b);
printf("%d %d\n", ans.first, ans.second);
}
}
}