SPOJ QTREE Query on a tree
题意:
给一颗n个点的树,有两种操作
CHANGE i ti : 把第i条边的权变为ti
QUERY a b : 问点a 到 点b 之间的边的最大权
思路:
树剖处理边权。
由于是边,所以只需要把边权处理到子节点上即可(查询的时候从节点2开始查询,或者把0处理成负无穷)
具体见代码:
const int maxn = + ;
const int maxnode = maxn * ; //线段树部分
int set_value, qL, qR;
int maxv[maxnode]; void update(int o, int L, int R)
{
if (qL <= L && R <= qR)
{
maxv[o] = set_value;
return;
}
int M = L + (R - L) / ;
if (qL <= M) update(lson);
if (qR > M) update(rson);
maxv[o] = max(maxv[o*], maxv[o*+]);
} int query(int o, int L, int R) {
if (qL <= L && R <= qR)
{
return maxv[o];
}
int M = L + (R - L) / ;
int ret = -INF;
if (qL <= M) ret = max(ret, query(lson));
if (qR > M) ret = max(ret, query(rson));
return ret;
} //树链剖分部分:
//
//u为连接的点,w为边权
struct Edge { int u, v, w; };
vector<int> G[maxn];
vector<Edge> e;
//往往是双向边
void add_edge(int u, int v, int w)
{
e.push_back((Edge){u, v, w});
G[u].push_back(v);
G[v].push_back(u);
} struct Node
{
int size, dep, son, top, fa, ti;
//依次表示第i个节点的:
//子节点数量,深度,所在链的顶端,重儿子,dfs序
} t[maxn]; int dfs_clock;//DFS时间序列 void dfs1(int u, int pa, int depth)//第一次DFS,得到size,dep,fa以及son的数据
{
t[u].son = ; //重儿子,为0表示没有重儿子
t[u].size = ; //节点数量
t[u].dep = depth;
t[u].fa = pa;
for (int i = ; i != G[u].size(); ++ i)
{
int v = G[u][i];
if (v == pa) continue;
dfs1(v, u, depth + );
t[u].size += t[v].size;
if (t[v].size > t[t[u].son].size) t[u].son = v;
}
} void dfs2(int u, int pa) // 得到时间戳等数据,u为当前节点,pa为父链顶端节点
{
t[u].ti = ++ dfs_clock; //u这个节点的时间戳是dfs_clock,dfs_clock下标是从1开始的,没有0!
t[u].top = pa; //top是u所在链的顶端
if (t[u].son != ) dfs2(t[u].son, t[u].top); //如果节点有重儿子,那么依旧是以pa为链顶端的一条链
for (int i = ; i != G[u].size(); ++ i)
{
int v = G[u][i];
if (v == t[u].son || v == t[u].fa) continue;//重儿子或者父节点,则跳过
dfs2(v, v);//新的一条链
}
} int n;
int lca(int x, int y)//更新x到y的之间所有的区间
{
int ret = -INF;
while (t[x].top != t[y].top)
{
if (t[t[x].top].dep < t[t[y].top].dep) swap(x,y); //x深 y浅
qL=t[t[x].top].ti;
qR=t[x].ti;
ret = max(ret, query(, , n));
x = t[t[x].top].fa;
}
if (t[x].dep > t[y].dep) swap(x, y);//x是上面一些的节点
if (x != y)
{
qL = t[x].ti + ;
qR = t[y].ti;
ret = max(ret, query(, , n));
}
return ret;
} void init()
{
memset(maxv, , sizeof(maxv));
dfs_clock = ;
scanf("%d", &n);
for (int i = ; i <= n; i++) G[i].clear();
e.clear();
int u, v, w;
for (int i = ; i < n; i++)
{
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
}
} void solve()
{
dfs1(, , );
dfs2(, ); for (int i = ; i < n; i++)
{
set_value = e[i-].w;
if (t[e[i-].u].dep < t[e[i-].v].dep)
qL = qR = t[e[i-].v].ti;
else
qL = qR = t[e[i-].u].ti;
update(, , n);
}
char op[];
int u, v;
while (true)
{
scanf("%s", op);
if (op[] == 'D') break;
scanf("%d%d", &u, &v);
if (op[] == 'Q')
{
printf("%d\n", lca(u, v));
}
else
{
set_value = v;
if (t[e[u-].u].dep < t[e[u-].v].dep)
qL = qR = t[e[u-].v].ti;
else
qL = qR = t[e[u-].u].ti;
update(, , n);
}
}
printf("\n");
} int main()
{
int T;
scanf("%d", &T);
while (T--)
{
init();
solve();
}
return ;
}
SPOJ QTREE Query on a tree的更多相关文章
- SPOJ QTREE Query on a tree 树链剖分+线段树
题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...
- spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)
传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...
- SPOJ QTREE Query on a tree --树链剖分
题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...
- SPOJ QTREE Query on a tree VI
You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are number ...
- SPOJ QTREE Query on a tree V
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are number ...
- SPOJ QTREE Query on a tree ——树链剖分 线段树
[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #incl ...
- SPOJ QTREE - Query on a tree 【树链剖分模板】
题目链接 引用到的大佬博客 代码来自:http://blog.csdn.net/jinglinxiao/article/details/72940746 具体算法讲解来自:http://blog.si ...
- SPOJ QTREE Query on a tree V ——动态点分治
[题目分析] QTREE4的弱化版本 建立出分治树,每个节点的堆表示到改点的最近白点距离. 然后分治树上一直向上,取min即可. 正确性显然,不用担心出现在同一子树的情况(不会是最优解),请自行脑补. ...
- SPOJ - QTREE Query on a tree题解
题目大意: 一棵树,有边权,有两个操作:1.修改一条边的权值:2.询问两点间路径上的边的权值的最大值. 思路: 十分裸的树链剖分+线段树,无非是边权要放到深度大的一端的点上,但是有两个坑爹的地方,改了 ...
随机推荐
- nodejs 访问mysql
安装 $ npm install mysql 简介 这个一个mysql的nodejs版本的驱动,是用JavaScript来编写的.不需要编译 这儿有个例子来示范如何使用: var mysql = re ...
- 使用Android点击按钮跳转页面
1.首先新建一个Android工程,命名为MyApp(名字可以自己随意起); 2.以原有的MainActivity.java文件为登录界面,然后在src文件中的包上面右击选择New目录下的Other中 ...
- Nginx 1.10.2 php 7 环境安装
1.安装编译工具和库文件,红色部分提示在centos镜像站点上查不到包,用yum安装的时候要认真看那些包没有找到,用yum的时候尽量不要使用-y选项 yum install gcc automake ...
- 从零搭建mongo分片集群的简洁方法
一.目录 1.mongo路径,config数据路径,shard数据路径
- UIApplication sharedApplication详细解释-IOS
iPhone应用程序是由主函数main启动,它负责调用UIApplicationMain函数,该函数的形式如下所示: int UIApplicationMain ( int argc, char *a ...
- Load Runner11录制脚本出现乱码的解决方法
方法一: 1.录制的脚本出现乱码 Go to Vugen -> Tools -> Recording Options -> Advancedb) Check the option ...
- table数据表格添加checkbox进行数据进行两个表格左右移动。
<table class="table table-hover table-striped table-condensed newDateList"> <thea ...
- JS js与css的动态加载
http://www.cnblogs.com/zhuimengdeyuanyuan/archive/2013/03/06/2946277.html
- mac xcworkspace xcodebuild
xcodebuild 在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念[4]: Workspace:简单来说,Workspace就是一个容器,在该容器中可以存放多个你创建的 ...
- MYSQL 基于GTID的复制
1.概述 从MYSQL5.6 开始,mysql开始支持GTID复制. 基于日志点复制的缺点: 从那个二进制日志的偏移量进行增量同步,如果指定错误会造成遗漏或者重复,导致数据不一致. 基于GTID复制: ...