题目背景
数据规模和spoj上有所不同
题目描述
给定一棵n个节点的树,有两个操作:
CHANGE i ti 把第i条边的边权变成ti
- QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0
输入输出格式
输入格式:
第一行输入一个n,表示节点个数
第二行到第n行每行输入三个数,ui,vi,wi,分别表示 ui,vi有一条边,边权是wi
第n+1行开始,一共有不定数量行,每一行分别有以下三种可能
CHANGE,QUERY同题意所述
DONE表示输入结束
输出格式:
对于每个QUERY操作,输出一个数,表示a b之间边权最大值
输入输出样例
说明
数据保证:
1 \leq≤ n \leq≤ 10^5105
操作次数 \leq≤ 3*10^53∗105
wi和ti \leq≤ 2^{31}-1231−1
树链剖分裸题,套一个线段树维护就好了。需要注意代码细节,比如节点编号要映射到序列上,但是直接用了节点编号修改的错误。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn = 3e5 + 5;
struct edge {
int v, w, next;
}e[maxn << 1];
int head[maxn], cnt, n, a, b, c, t, f;
char s;
inline char gc(){
static char buf[2000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 2000000, stdin), p1 == p2) ? EOF : *p1++;
}
inline void read(int & x) {
x = 0; static char c = gc();
while(!isdigit(c)) c = gc();
while(isdigit(c)) x = x * 10 + c - '0', c = gc();
}
inline void rc(char & x) {
x = gc();
while(x != 'Q' && x != 'C' && x != 'D') x = gc();;
}
void adde(const int &u, const int &v, const int &w) {
e[++cnt] = (edge) {v, w, head[u]};
head[u] = cnt;
}
int fa[maxn], son[maxn], size[maxn], id[maxn], d[maxn], top[maxn];
int idcnt, num[maxn], ni[maxn], ow[maxn];
void dfs1(int u, int p) {
fa[u] = p, d[u] = d[p] + 1;
size[u] = 1;
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(v == p) continue;
dfs1(v, u), size[u] += size[v], ow[v] = e[i].w;
ni[((i + 1) >> 1)] = v;
if(size[v] > size[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp, id[u] = ++idcnt, num[idcnt] = ow[u];
if(son[u]) dfs2(son[u], tp);
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
namespace SGT {
int mx[maxn << 2], cnt;
void push_up(int rt) {mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);}
void build(int l, int r, int rt) {
if(l == r) {mx[rt] = num[l];return ;}
int mid = l + r >> 1;
build(l, mid, rt << 1), build(mid + 1, r, rt << 1 | 1);
push_up(rt);
}
void edit(int pos, int tl, int tr, int dt, int rt) {
if(tl == tr) {num[tl] = dt, mx[rt] = dt;return ;}
int mid = tl + tr >> 1;
if(pos <= mid) edit(pos, tl, mid, dt, rt << 1);
else edit(pos, mid + 1, tr, dt, rt << 1 | 1);
push_up(rt);
}
int query(int l, int r, int tl, int tr, int rt) {
if(l == tl && r == tr) return mx[rt];
int mid = tl + tr >> 1;
if(r <= mid) return query(l, r, tl, mid, rt << 1);
else if(l > mid) return query(l, r, mid + 1, tr, rt << 1 | 1);
else return max(query(l, mid, tl, mid, rt << 1), query(mid + 1, r, mid + 1, tr, rt << 1 | 1));
}
}
#define Q(l, r) query((l), (r), 1, n, 1)
int Gmax(int u, int v) {
using namespace SGT;
int ans = 0;
while(top[u] != top[v]) {
if(d[top[u]] < d[top[v]]) swap(u, v);
ans = max(ans, Q(id[top[u]], id[u])), u = fa[top[u]];
}
if(d[u] > d[v]) ans = max(ans, Q(id[v] + 1, id[u]));
if(d[v] > d[u]) ans = max(ans, Q(id[u] + 1, id[v]));
return ans;
}
int main() {
read(n);
for(register int i = 1; i < n; ++i) {
read(a), read(b), read(c);
adde(a, b, c), adde(b, a, c);
}
dfs1(1, 0), dfs2(1, 1);
SGT::build(1, n, 1);
while(1) {
rc(s);
if(s == 'D') break;
read(a), read(b);
if(s == 'Q') printf("%d\n", Gmax(a, b));
else SGT::edit(id[ni[a]], 1, idcnt, b, 1);
}
return 0;
}
rockdu
没有帐号? 立即注册