相信你们都有题目了。。。(我就偷个懒)
想说,为什么一道模板题做了这么久?(好累)
首先,我的想法是将点换为边的编号来存储,码了半天,没码出来,把自己脑子搞昏了,就将边换为点存储。具体方法如下:
首先,我们发现一个点与它的爸爸的边和它本身是一一对应关系,受到启发我们用点来保存边权。
其次,因为有取相反数的操作,我终于灵机一动:存储max和min,取反时再倒过来。
大体思路有了,我们还有几个实际问题要解决。
- CHANGE操作是用边来处理,我们可以再用一个op数组存储对应关系。
- 虽然上文有匹配了,可以发现1号节点是没有匹配的边的。但如果放任不管的话,如果最终答案是负数,从这个节点上来最终答案会变成0。所以我们要赋初值。
- 然后,我们需要改进一下查询。当x和y不在一条链(这里指重链或轻链)时可以这么写,因为正好算出连接2条链的边。而如果在一条链上就会错:查询x和f[x]之间的边(只有一条),这样算会算爸爸的爸爸的边。
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
const int N = 10002, INF = (1 << 30) - 1;
struct node {
int u, num;
};
struct tree {
int mx, mn;
}st[N << 2];
string ac;
int la[N << 2], op[N], son[N], ans, cnt, n, w[N], d[N], f[N], s[N], top[N], id[N];
vector <node> G[N];
void init(const int x, const int ba) {
s[x] = 1;
d[x] = d[ba] + 1;
f[x] = ba;
for(int i = 0; i < G[x].size(); i ++) {
int v = G[x][i].u;
if(v == ba)
continue;
op[G[x][i].num] = v;
init(v, x);
s[x] += s[v];
if(s[v] > s[son[x]] || son[x] == 0)
son[x] = v;
}
}
void dfs(const int x, const int t) {
id[x] = ++ cnt;
top[x] = t;
if(son[x] == 0)
return;
dfs(son[x], t);
for(int i = 0; i < G[x].size(); i ++) {
int v = G[x][i].u;
if(v == f[x] || v == son[x])
continue;
dfs(v, v);
}
}
void pushDown(const int x) {
int l = (x << 1), r = (x << 1 | 1);
if(la[x] == -1) {
swap(st[l].mx, st[l].mn);
swap(st[r].mx, st[r].mn);
st[l].mx *= -1;
st[l].mn *= -1;
st[r].mx *= -1;
st[r].mn *= -1;
}
la[l] *= la[x];
la[r] *= la[x];
la[x] = 1;
}
void addC(const int x, const int l, const int r, const int L, const int R, const int k) {
if(l > R || r < L)
return;
if(l >= L && r <= R) {
if ( L == 1 && R == 1 ) {
st[x].mn = k;
st[x].mx = -k;
}
else {
st[x].mn = k;
st[x].mx = k;
}
return;
}
pushDown(x);
int mid = l + r >> 1;
addC(x << 1, l, mid, L, R, k);
addC(x << 1 | 1, mid + 1, r, L, R, k);
st[x].mx = max(st[x << 1].mx, st[x << 1 | 1].mx);
st[x].mn = min(st[x << 1].mn, st[x << 1 | 1].mn);
}
void addN(const int x, const int l, const int r, const int L, const int R) {
if(l > r)
return;
if(l > R || r < L)
return;
if(l >= L && r <= R) {
swap(st[x].mn, st[x].mx);
st[x].mn *= -1;
st[x].mx *= -1;
la[x] = -la[x];//D
return;
}
pushDown(x);
int mid = l + r >> 1;
addN(x << 1, l, mid, L, R);
addN(x << 1 | 1, mid + 1, r, L, R);
st[x].mx = max(st[x << 1].mx, st[x << 1 | 1].mx);
st[x].mn = min(st[x << 1].mn, st[x << 1 | 1].mn);
}
int ask(const int x, const int l, const int r, const int L, const int R) {
if(l > r)
return -INF;//C
if(l > R || r < L)
return -INF;
if(l >= L && r <= R)
return st[x].mx;
pushDown(x);
int mid = l + r >> 1;
return max(ask(x << 1, l, mid, L, R), ask(x << 1 | 1, mid + 1, r, L, R));
}
int main() {
int a, b, x, y;
scanf("%d", &n);
for(int i = 1; i < n; i ++) {
scanf("%d %d %d", &a, &b, &w[i]);
G[a].push_back((node) {b, i});
G[b].push_back((node) {a, i});
}
init(1, 0);
dfs(1, 1);
addC(1, 1, cnt, id[1], id[1], INF);
for(int i = 1; i < n; i ++)
addC(1, 1, cnt, id[op[i]], id[op[i]], w[i]);//A
while(1) {
cin >> ac;
if(ac[0] == 'D')
break;
else if(ac[0] == 'Q') {
scanf("%d %d", &x, &y);
ans = -INF;//B
while(top[x] != top[y]) {
if(d[top[x]] >= d[top[y]]) {
ans = max(ans, ask(1, 1, cnt, id[top[x]], id[x]));
x = f[top[x]];
}
else {
ans = max(ans, ask(1, 1, cnt, id[top[y]], id[y]));
y = f[top[y]];
}
}
if(id[x] <= id[y])
ans = max(ans, ask(1, 1, cnt, id[x] + 1, id[y]));
else
ans = max(ans, ask(1, 1, cnt, id[y] + 1, id[x]));
printf("%d\n", ans);
}
else if(ac[0] == 'C') {
scanf("%d %d", &a, &b);
addC(1, 1, cnt, id[op[a]], id[op[a]], b);
}
else {
scanf("%d %d", &x, &y);
while(top[x] != top[y]) {
if(d[top[x]] >= d[top[y]]) {
addN(1, 1, cnt, id[top[x]], id[x]);
x = f[top[x]];
}
else {
addN(1, 1, cnt, id[top[y]], id[y]);
y = f[top[y]];
}
}
if(id[x] <= id[y])
addN(1, 1, cnt, id[x] + 1, id[y]);
else
addN(1, 1, cnt, id[y] + 1, id[x]);
}
}
return 0;
}
注:
A:这个地方要用id数组哟,我栽在这好久。
B:ans不要赋值为0!!!!!!
C:l可能大于r,返回极小值。
D:此时不能直接赋值为-1,因为会有重复取反的操作。
好了就到这里了,如有错误,请在评论区指出,谢谢!!!