poj 3237 Tree 树链剖分
2015-03-17 18:15
337 查看
题目链接:http://poj.org/problem?id=3237
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
题意描述:一棵树有n个节点和n-1条边,每条边有一个权值。现在给出三种操作:
CHANGE I V:把第i条边的值改为v
NEGATE A B:把A到B的路径上的所有边的值取反(正为负,负改为正)
QUERY A B:询问A到B的路径上的边权值的最大值。
算法分析:树链剖分解决。把边权值移到节点上面,由于操作上有对值取反,所有我们不止要运用线段树统计区间最大值maxnum,还要统计区间最小值minnum,这样在取反操作后,maxnum=-maxnum,minnum=-minnum,再把两个值交换:swap(maxnum,minnum)即可。
说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGEi v | Change the weight of the ith edge to v |
NEGATEa b | Negate the weight of every edge on the path from a to b |
QUERYa b | Find the maximum weight of edges on the path from a to b |
CHANGE I V:把第i条边的值改为v
NEGATE A B:把A到B的路径上的所有边的值取反(正为负,负改为正)
QUERY A B:询问A到B的路径上的边权值的最大值。
算法分析:树链剖分解决。把边权值移到节点上面,由于操作上有对值取反,所有我们不止要运用线段树统计区间最大值maxnum,还要统计区间最小值minnum,这样在取反操作后,maxnum=-maxnum,minnum=-minnum,再把两个值交换:swap(maxnum,minnum)即可。
说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<vector> #define inf 0x7fffffff using namespace std; const int maxn=100000+10; struct Edge { int to,next; }edge[maxn*2]; int head[maxn],edgenum; int top[maxn];//top[v]表示v所在的重链的顶端节点 int fa[maxn]; //父亲节点 int dep[maxn];//深度 int siz[maxn];//siz[v]表示以v为根的子树的节点数 int tid[maxn];//tid[v]表示v与其父亲节点的连边在线段树中的位置 int tid2[maxn];//和tid数组相反 int son[maxn];//重儿子 int pos; void init() { edgenum=0; memset(head,-1,sizeof(head)); pos=0; memset(son,-1,sizeof(son)); } void addedge(int u,int v) { edge[edgenum].to=v ;edge[edgenum].next=head[u]; head[u]=edgenum++; edge[edgenum].to=u ;edge[edgenum].next=head[v]; head[v]=edgenum++; } void dfs1(int u,int pre,int d) //第一遍dfs求出fa,dep,siz,son { dep[u]=d; fa[u]=pre; siz[u]=1; for (int i=head[u] ;i != -1 ;i=edge[i].next) { int v=edge[i].to; if (v != pre) { dfs1(v,u,d+1); siz[u] += siz[v]; if (son[u] == -1 || siz[v]>siz[son[u]]) son[u]=v; } } } void dfs2(int u,int tp) //第二遍dfs求出top和tid { top[u]=tp; tid[u]= ++pos; tid2[pos]=u; if (son[u] == -1) return; dfs2(son[u],tp); for (int i=head[u] ;i != -1 ;i=edge[i].next) { int v=edge[i].to; if (v != son[u] && v != fa[u]) dfs2(v,v); } } //线段树 struct node { int l,r; int Max; int Min; int ne; }segTree[maxn*3]; void build(int l,int r,int rt) { segTree[rt].l=l; segTree[rt].r=r; segTree[rt].Max=0; segTree[rt].Min=0; segTree[rt].ne=0; if (l==r) return ; int mid=(l+r)/2; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void PushUP(int rt) { segTree[rt].Max = max(segTree[rt<<1].Max,segTree[rt<<1|1].Max); segTree[rt].Min = min(segTree[rt<<1].Min,segTree[rt<<1|1].Min); } void PushDown(int rt) { if (segTree[rt].l == segTree[rt].r) return ; if (segTree[rt].ne) { segTree[rt<<1].Max = -segTree[rt<<1].Max; segTree[rt<<1].Min = -segTree[rt<<1].Min; swap(segTree[rt<<1].Min,segTree[rt<<1].Max); segTree[rt<<1|1].Max = -segTree[rt<<1|1].Max; segTree[rt<<1|1].Min = -segTree[rt<<1|1].Min; swap(segTree[rt<<1|1].Max,segTree[rt<<1|1].Min); segTree[rt<<1].ne ^= 1; segTree[rt<<1|1].ne ^= 1; segTree[rt].ne = 0; } } void update(int k,int val,int rt) // 更新线段树的第k个值为val { if(segTree[rt].l == k && segTree[rt].r == k) { segTree[rt].Max = val; segTree[rt].Min = val; segTree[rt].ne = 0; return; } PushDown(rt); int mid = (segTree[rt].l + segTree[rt].r)/2; if(k <= mid)update(k,val,rt<<1); else update(k,val,(rt<<1)|1); PushUP(rt); } void ne_update(int l,int r,int rt) // 更新线段树的区间[l,r]取反 { if (segTree[rt].l == l && segTree[rt].r == r) { segTree[rt].Max = -segTree[rt].Max; segTree[rt].Min = -segTree[rt].Min; swap(segTree[rt].Max,segTree[rt].Min); segTree[rt].ne ^= 1; return; } PushDown(rt); int mid = (segTree[rt].l + segTree[rt].r)/2; if (r <= mid) ne_update(l,r,rt<<1); else if (l > mid) ne_update(l,r,(rt<<1)|1); else { ne_update(l,mid,rt<<1); ne_update(mid+1,r,(rt<<1)|1); } PushUP(rt); } int query(int l,int r,int rt) //查询线段树中[l,r] 的最大值 { if (segTree[rt].l == l && segTree[rt].r == r) return segTree[rt].Max; PushDown(rt); int mid = (segTree[rt].l+segTree[rt].r)>>1; if (r <= mid) return query(l,r,rt<<1); else if (l > mid) return query(l,r,(rt<<1)|1); else return max(query(l,mid,rt<<1),query(mid+1,r,(rt<<1)|1)); PushUP(rt); } int findmax(int u,int v)//查询u->v边的最大值 { int f1 = top[u], f2 = top[v]; int tmp = -100000000; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2); swap(u,v); } tmp = max(tmp,query(tid[f1],tid[u],1)); u = fa[f1]; f1 = top[u]; } if(u == v)return tmp; if(dep[u] > dep[v]) swap(u,v); return max(tmp,query(tid[son[u]],tid[v],1)); } void Negate(int u,int v) { int f1=top[u],f2=top[v]; while (f1 != f2) { if (dep[f1]<dep[f2]) { swap(f1,f2); swap(u,v); } ne_update(tid[f1],tid[u],1); u=fa[f1] ;f1=top[u]; } if (u==v) return; if (dep[u]>dep[v]) swap(u,v); return ne_update(tid[son[u] ],tid[v],1); } int e[maxn][3]; int main() { int T; int n; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); for(int i = 0;i < n-1;i++) { scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); addedge(e[i][0],e[i][1]); } dfs1(1,0,0); dfs2(1,1); build(1,n,1); for (int i = 0;i < n-1; i++) { if (dep[e[i][0]]>dep[e[i][1]]) swap(e[i][0],e[i][1]); update(tid[e[i][1]],e[i][2],1); } char op[10]; int u,v; while (scanf("%s",op) == 1) { if (op[0] == 'D') break; scanf("%d%d",&u,&v); if (op[0]=='Q') printf("%d\n",findmax(u,v));//查询u->v路径上边权的最大值 else if (op[0]=='C') update(tid[e[u-1][1]],v,1);//改变第u条边的值为v else Negate(u,v); } } return 0; }
相关文章推荐
- POJ 3237 Tree 树链剖分
- POJ 3237 Tree(树链剖分-线段树点更新-区间更新-区间最值查询-入边)
- POJ 3237 Tree (树链剖分)
- POJ-3237:Tree(树链剖分)
- POJ 3237 Tree(树链剖分模板)
- 【POJ】3237 Tree 树链剖分
- POJ 3237 - Tree(树链剖分)
- POJ 3237 Tree 树链剖分
- POJ-3237 Tree(树链剖分)
- POJ 3237 Tree(树链剖分 + 单点更新 + 区间更新 + 区间查询)
- POJ 3237 Tree(树链剖分)
- 【树链剖分】 POJ 3237 Tree
- poj 3237 Tree 树链剖分
- POJ 3237 Tree 树链剖分
- POJ 3237 Tree(树链剖分——边权)
- poj 3237 Tree 树链剖分 线段树
- POJ 3237 Tree (树链剖分 路径更新)
- POJ 3237 Tree 树链剖分
- poj 3237 Tree(树链剖分,线段树)
- POJ 3237 Tree 树链剖分 线段树