poj 3237 Tree 树链剖分
题目链接: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:
CHANGE i v |
Change the weight of the ith edge to v |
NEGATE a b |
Negate the weight of every edge on the path from a to b |
QUERY a b |
Find the maximum weight of edges on the path from a to b |
题意描述:一棵树有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)即可。
说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
using namespace std;
const int maxn=+; struct Edge
{
int to,next;
}edge[maxn*];
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=;
memset(head,-,sizeof(head));
pos=;
memset(son,-,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]=;
for (int i=head[u] ;i != - ;i=edge[i].next)
{
int v=edge[i].to;
if (v != pre)
{
dfs1(v,u,d+);
siz[u] += siz[v];
if (son[u] == - || 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] == -) return;
dfs2(son[u],tp);
for (int i=head[u] ;i != - ;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*]; void build(int l,int r,int rt)
{
segTree[rt].l=l;
segTree[rt].r=r;
segTree[rt].Max=;
segTree[rt].Min=;
segTree[rt].ne=;
if (l==r) return ;
int mid=(l+r)/;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
}
void PushUP(int rt)
{
segTree[rt].Max = max(segTree[rt<<].Max,segTree[rt<<|].Max);
segTree[rt].Min = min(segTree[rt<<].Min,segTree[rt<<|].Min);
}
void PushDown(int rt)
{
if (segTree[rt].l == segTree[rt].r) return ;
if (segTree[rt].ne)
{
segTree[rt<<].Max = -segTree[rt<<].Max;
segTree[rt<<].Min = -segTree[rt<<].Min;
swap(segTree[rt<<].Min,segTree[rt<<].Max);
segTree[rt<<|].Max = -segTree[rt<<|].Max;
segTree[rt<<|].Min = -segTree[rt<<|].Min;
swap(segTree[rt<<|].Max,segTree[rt<<|].Min);
segTree[rt<<].ne ^= ;
segTree[rt<<|].ne ^= ;
segTree[rt].ne = ;
}
} 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 = ;
return;
}
PushDown(rt);
int mid = (segTree[rt].l + segTree[rt].r)/;
if(k <= mid)update(k,val,rt<<);
else update(k,val,(rt<<)|);
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 ^= ;
return;
}
PushDown(rt);
int mid = (segTree[rt].l + segTree[rt].r)/;
if (r <= mid) ne_update(l,r,rt<<);
else if (l > mid) ne_update(l,r,(rt<<)|);
else
{
ne_update(l,mid,rt<<);
ne_update(mid+,r,(rt<<)|);
}
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)>>;
if (r <= mid) return query(l,r,rt<<);
else if (l > mid) return query(l,r,(rt<<)|);
else return max(query(l,mid,rt<<),query(mid+,r,(rt<<)|));
PushUP(rt);
}
int findmax(int u,int v)//查询u->v边的最大值
{
int f1 = top[u], f2 = top[v];
int tmp = -;
while(f1 != f2)
{
if(dep[f1] < dep[f2])
{
swap(f1,f2);
swap(u,v);
}
tmp = max(tmp,query(tid[f1],tid[u],));
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],));
} 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],);
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],);
} int e[maxn][];
int main()
{
int T;
int n;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i = ;i < n-;i++)
{
scanf("%d%d%d",&e[i][],&e[i][],&e[i][]);
addedge(e[i][],e[i][]);
}
dfs1(,,);
dfs2(,);
build(,n,);
for (int i = ;i < n-; i++)
{
if (dep[e[i][]]>dep[e[i][]])
swap(e[i][],e[i][]);
update(tid[e[i][]],e[i][],);
}
char op[];
int u,v;
while (scanf("%s",op) == )
{
if (op[] == 'D') break;
scanf("%d%d",&u,&v);
if (op[]=='Q')
printf("%d\n",findmax(u,v));//查询u->v路径上边权的最大值
else if (op[]=='C')
update(tid[e[u-][]],v,);//改变第u条边的值为v
else Negate(u,v);
}
}
return ;
}
poj 3237 Tree 树链剖分的更多相关文章
- POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)
题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...
- POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12247 Accepted: 3151 Descriptio ...
- poj 3237 Tree 树链剖分+线段树
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- poj 3237 Tree(树链拆分)
题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询a ...
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
随机推荐
- [leetcode]_Binary Tree Inorder Traversal
题目:二叉树的中序遍历. 思路:用递归来写中序遍历非常简单.但是题目直接挑衅说,----->"Recursive solution is trivial".好吧.谁怕谁小狗. ...
- Windows7下Microsoft Office Excel 不能访问文件解决方案
1).开始--〉运行--〉cmd 2)命令提示符下面,输入mmc -32,打开32的控制台 3).文件菜单中,添加删除管理单元--〉组件服务 4).在"DCOM配置"中找到&quo ...
- Delphi的基本函数
Delphi的基本函数 函数由一句或多句代码组成,可以实现某个特定的功能.使用函数可以使代码更加易读.易懂,加快编程速度及减少重复代码.过程与函数类似,过程与函数最重要的区别在于,过程没有返回值,而函 ...
- Sql Server数据库之通过SqlBulkCopy快速插入大量数据
废话不多说,直接上代码 /// <summary> /// 海量数据插入方法 /// </summary> /// <param name="connectio ...
- 实战Django:官方实例Part6
我们终于迎来了官方实例的最后一个Part.在这一节中,舍得要向大家介绍Django的静态文件管理. 现在,我们要往这个投票应用里面添加一个CSS样式表和一张图片. 一个完整的网页文件,除了html文档 ...
- linux中fork()函数详解
一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同, ...
- hdu 5273 Dylans loves sequence
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5273 Dylans loves sequence Description Dylans is give ...
- 从零开始学ios开发(三):第一个有交互的app
感谢大家的关注,也给我一份动力,让我继续前进.有了自己的家庭有了孩子,过着上有老下有小的生活,能够挤出点时间学习真的很难,每天弄好孩子睡觉已经是晚上10点左右了,然后再弄自己的事情,一转眼很快就到12 ...
- [转]理解与使用Javascript中的回调函数
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...
- Visio编辑数据库模型列
Visio编辑数据库模型列:邮件group->Open实体,进入实体属性编辑界面,按回车可以添加.