题目:Tree
题意:给定一棵树,树边有权值,然后三种操作:
CHANGE i v:将编号为i的边的权值修改为v;
NEGATE a b:将树上a到b的路径经过的边的权值全部取反,即改变它们的正负号;
QUERY a b:询问树上a到b的路径经过的边的权值的最大值;
单条链的问题用线段树很好解决,结点记录当前区间的最大值和最小值,修改是单点修改,没什么问题。对于区间取反的,打个懒惰标记,然后最大值变成原先最小值的相反数,最小值变成原先最大值的相反数。
所以这个题目按照这个思想进行树链剖分后,每条链按照上述方案维护线段树即可。
之前在HDU4718这题里面,用了个map来映射出每条链对应的节点的权值,详情见我上一篇文章。
不过这题用了map却超时了,毕竟map套map的查询复杂度是(log N)^2。
然后想到可以用vector来搞定,因为不管是之前的加入map也好,现在的加入vector也好,添加顺序是按照链上从左到右添加的,所以vector存储的顺序跟链上结点顺序是对应的。
所以查询变成O(1),改成vector就AC了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int N = 10010;
inline void in(int &x){
bool mk = 0;
x = 0;
char c=getchar();
while(c<48 || c>57){
if(c=='-') mk=1;
c=getchar();
}
while(c>=48 && c<=57){
x = x*10+c-48;
c = getchar();
}
if(mk) x = -x;
}
#define pb push_back
#define cur tr[o]
#define lson tr[o].lch
#define rson tr[o].rch
#define lchd tr[tr[o].lch]
#define rchd tr[tr[o].rch]
struct Edge{
int to, id;
Edge(){}
Edge(int to, int id):to(to),id(id){}
};
vector<Edge> V[N];
struct TreeNode{
int l, r, Max, Min;
bool f;
int lch, rch;
}tr[N*10];
vector<int> MP[N];
int n, path_cnt, node_cnt;
int father[N];
int belong[N];
int size[N];
int rank[N];
int path_size[N];
int path_top[N];
int path_dep[N];
int bottom[N];//从根节点出发形成的树,每条边下面的结点的编号
int weight[N];//边的权值
int val[N];//结点到父结点的边的权值
int tree[N];
/*线段树部分*/
void maintain(int o){
cur.Max = max(lchd.Max, rchd.Max);
cur.Min = min(lchd.Min, rchd.Min);
}
void build(int id, int o, int ll, int rr){
cur.l=ll; cur.r=rr;
cur.f = 0;
if(ll<rr){
int m = (ll+rr)>>1;
lson = ++node_cnt;
build(id, lson, ll, m);
rson = ++node_cnt;
build(id, rson, m+1, rr);
maintain(o);
}
else{
cur.Max = cur.Min = MP[id][ll-1];
}
}
void update(int o, int ll, int rr);
void pushdown(int o){
if(cur.f){
int m = (cur.l + cur.r)>>1;
update(lson, cur.l, m);
update(rson, m+1, cur.r);
cur.f = 0;
}
}
void update(int o, int ll, int rr){
if(cur.l==ll && cur.r==rr){
int tmp = cur.Min;
cur.Min = -cur.Max;
cur.Max = -tmp;
cur.f ^= 1;
return;
}
int m = (cur.l+cur.r)>>1;
pushdown(o);
if(rr<=m) update(lson, ll, rr);
else if(ll>m) update(rson, ll, rr);
else{
update(lson, ll, m);
update(rson, m+1, rr);
}
maintain(o);
}
void change(int o, int p, int v){
if(cur.l==p && cur.r==p){
cur.Max = cur.Min = v;
return;
}
int m = (cur.l+cur.r)>>1;
pushdown(o);
if(p<=m) change(lson, p, v);
else change(rson, p, v);
maintain(o);
}
int query(int o, int ll, int rr){
if(cur.l==ll && cur.r==rr) return cur.Max;
pushdown(o);
int ans;
int m = (cur.l+cur.r)>>1;
if(rr<=m) ans = query(lson, ll, rr);
else if(ll>m) ans = query(rson, ll, rr);
else ans = max(query(lson, ll, m), query(rson, m+1, rr));
maintain(o);
return ans;
}
/*以上是线段树的代码*/
void dfs(int x, int dep){
int key=-1;
int M = 0;
size[x]=1;
for(int i=0; i<V[x].size(); i++){
Edge &e = V[x][i];
if(e.to == father[x]) continue;
father[e.to] = x;
bottom[e.id] = e.to;
val[e.to] = weight[e.id];
dfs(e.to, dep+1);
size[x]+=size[e.to];
if(size[e.to]>M){
M = size[e.to];
key = i;
}
}
belong[x]=0;
for(int i=0; i<V[x].size(); i++){
Edge &e = V[x][i];
if(e.to == father[x]) continue;
if(i==key){
belong[x] = belong[e.to];
rank[x] = rank[e.to]+1;
}
else{
int p = belong[e.to];
path_size[p] = rank[e.to];
path_dep[p] = dep;
path_top[p] = e.to;
}
}
if(!belong[x]){
belong[x] = ++path_cnt;
rank[x] = 1;
MP[path_cnt].clear();
}
MP[belong[x]].pb(val[x]);
}
void init(){
path_cnt = node_cnt = 0;
father[1] = 0;
val[1] = 0;
dfs(1, 1);
int p = belong[1];
path_size[p] = rank[1];
path_top[p] = 1;
path_dep[p] = 0;
for(int i=1; i<=path_cnt; i++){
tree[i] = ++node_cnt;
build(i, tree[i], 1, path_size[i]);
}
}
void C(int x, int v){
int p = bottom[x];
change(tree[belong[p]], rank[p], v);
}
void neg(int a, int b){
int x=belong[a];
int y=belong[b];
while(x!=y){
if(path_dep[x]>path_dep[y]){
update(tree[x], rank[a], path_size[x]);
a = father[path_top[x]];
x = belong[a];
}
else{
update(tree[y], rank[b], path_size[y]);
b = father[path_top[y]];
y = belong[b];
}
}
if(a!=b){
if(rank[a]>rank[b]){
update(tree[x], rank[b], rank[a]-1);
}
else{
update(tree[x], rank[a], rank[b]-1);
}
}
}
int Q(int a, int b){
bool flag = 0;
int ans, v;
int x = belong[a];
int y = belong[b];
while(x!=y){
if(path_dep[x]>path_dep[y]){
v = query(tree[x], rank[a], path_size[x]);
a = father[path_top[x]];
x = belong[a];
}
else{
v = query(tree[y], rank[b], path_size[y]);
b = father[path_top[y]];
y = belong[b];
}
if(!flag) ans = v;
else ans = max(ans, v);
flag = 1;
}
if(a!=b){
if(rank[a]>rank[b]){
v = query(tree[x], rank[b], rank[a]-1);
}
else{
v = query(tree[x], rank[a], rank[b]-1);
}
if(!flag) ans = v;
else ans = max(ans, v);
}
return ans;
}
int main(){
int T;
in(T);
while(T--){
in(n);
int a, b;
for(int i=1; i<=n; i++) V[i].clear();
for(int i=1; i<n; i++){
in(a); in(b); in(weight[i]);
V[a].pb(Edge(b, i));
V[b].pb(Edge(a, i));
}
init();
char op[10];
while(~scanf("%s", op) && op[0]!='D'){
in(a); in(b);
if(op[0]=='C'){
C(a, b);
}
else if(op[0]=='N'){
neg(a, b);
}
else{
printf("%d\n",Q(a,b));
}
}
}
return 0;
}