题目大意:给出一棵树,支持以下操作: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; }
时间: 2024-10-10 16:41:05