题目大意:给出一棵树,支持以下操作:1.改变一条边的边权。2.将x到y路径的权值取反。3.查询x到y路径上最大值,最小值和权值和。
思路:好裸的链剖水题啊,唯一麻烦一点地是权值放在了边上,注意一下处理就没问题了。。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 40010
#define INF 0x3f3f3f3f
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
#define min(a,b) ((a) < (b) ? (a):(b))
#define max(a,b) ((a) > (b) ? (a):(b))
int points,asks;
int head[MAX],total;
int _next[MAX << 1],aim[MAX << 1];
struct Edge{
int x,y,len;
int pos;
Edge(int _,int __,int ___):x(_),y(__),len(___) {}
Edge() {}
}edge[MAX];
inline void Add(int x,int y)
{
_next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
int father[MAX],deep[MAX],son[MAX],size[MAX];
void _DFS(int x,int last)
{
father[x] = last;
deep[x] = deep[last] + 1;
size[x] = 1;
int max_size = 0;
for(int i = head[x]; i; i = _next[i]) {
if(aim[i] == last) continue;
_DFS(aim[i],x);
size[x] += size[aim[i]];
if(size[aim[i]] > max_size)
max_size = size[aim[i]],son[x] = aim[i];
}
}
int pos[MAX],top[MAX],cnt;
void DFS(int x,int last,int _top)
{
pos[x] = ++cnt;
top[x] = _top;
if(son[x]) DFS(son[x],x,_top);
for(int i = head[x]; i; i = _next[i]) {
if(aim[i] == last || aim[i] == son[x]) continue;
DFS(aim[i],x,aim[i]);
}
}
struct SegTree{
int sum,_min,_max;
bool inv;
SegTree(int _ = 0,int __ = INF,int ___ = -INF):sum(_),_min(__),_max(___) {}
void Inv() {
inv ^= 1;
sum *= -1;
int t = _max;
_max = -_min;
_min = -t;
}
}tree[MAX << 2];
inline void PushUp(int pos)
{
tree[pos].sum = tree[LEFT].sum + tree[RIGHT].sum;
tree[pos]._min = min(tree[LEFT]._min,tree[RIGHT]._min);
tree[pos]._max = max(tree[LEFT]._max,tree[RIGHT]._max);
}
inline SegTree PushUp(SegTree a,SegTree b)
{
SegTree re;
re.sum = a.sum + b.sum;
re._min = min(a._min,b._min);
re._max = max(a._max,b._max);
return re;
}
inline void PushDown(int pos)
{
if(tree[pos].inv) {
tree[LEFT].Inv();
tree[RIGHT].Inv();
tree[pos].inv = false;
}
}
void Modify(int l,int r,int x,int pos,int c)
{
if(l == r) {
tree[pos].sum = tree[pos]._min = tree[pos]._max = c;
return ;
}
PushDown(pos);
int mid = (l + r) >> 1;
if(x <= mid) Modify(l,mid,x,LEFT,c);
else Modify(mid + 1,r,x,RIGHT,c);
PushUp(pos);
}
void Change(int l,int r,int x,int y,int pos)
{
if(l == x && r == y) {
tree[pos].Inv();
return ;
}
PushDown(pos);
int mid = (l + r) >> 1;
if(y <= mid) Change(l,mid,x,y,LEFT);
else if(x > mid) Change(mid + 1,r,x,y,RIGHT);
else {
Change(l,mid,x,mid,LEFT);
Change(mid + 1,r,mid + 1,y,RIGHT);
}
PushUp(pos);
}
inline void Change(int x,int y)
{
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]])
swap(x,y);
Change(1,points,pos[top[x]],pos[x],1);
x = father[top[x]];
}
if(x == y) return ;
if(deep[x] < deep[y]) swap(x,y);
Change(1,points,pos[y] + 1,pos[x],1);
}
SegTree Ask(int l,int r,int x,int y,int pos)
{
if(l == x && r == y) return tree[pos];
PushDown(pos);
int mid = (l + r) >> 1;
if(y <= mid) return Ask(l,mid,x,y,LEFT);
if(x > mid) return Ask(mid + 1,r,x,y,RIGHT);
SegTree left = Ask(l,mid,x,mid,LEFT);
SegTree right = Ask(mid + 1,r,mid + 1,y,RIGHT);
return PushUp(left,right);
}
inline SegTree Ask(int x,int y)
{
SegTree re(0,INF,-INF);
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]])
swap(x,y);
re = PushUp(re,Ask(1,points,pos[top[x]],pos[x],1));
x = father[top[x]];
}
if(x == y) return re;
if(deep[x] < deep[y]) swap(x,y);
re = PushUp(re,Ask(1,points,pos[y] + 1,pos[x],1));
return re;
}
char c[10];
int main()
{
cin >> points;
for(int x,y,z,i = 1; i < points; ++i) {
scanf("%d%d%d",&x,&y,&z);
x++,y++;
Add(x,y),Add(y,x);
edge[i] = Edge(x,y,z);
}
_DFS(1,0);
DFS(1,0,1);
for(int i = 1; i < points; ++i) {
edge[i].pos = deep[edge[i].x] > deep[edge[i].y] ? pos[edge[i].x]:pos[edge[i].y];
Modify(1,points,edge[i].pos,1,edge[i].len);
}
cin >> asks;
for(int x,y,i = 1; i <= asks; ++i) {
scanf("%s%d%d",c,&x,&y);
if(c[0] == 'C') Modify(1,points,edge[x].pos,1,y);
else if(c[0] == 'N') Change(x + 1,y + 1);
else {
SegTree ans = Ask(x + 1,y + 1);
if(c[0] == 'S') printf("%d\n",ans.sum);
else if(c[1] == 'I') printf("%d\n",ans._min);
else printf("%d\n",ans._max);
}
}
return 0;
}