SPOJ375 Query on a tree(LCT边权)
之前做了两道点权的LCT,这次做一下边权的LCT.上网找了一下资料,发现对于边权的LCT有这么两种处理方法,一种是每条边建一个点,于是边权就转成点权了。另外一种则是每个边权对应到点权上,也就是每个点对应它的父边,这就要求树不能换根,不换根提路径是有点蛋疼的,所以就需要知道怎么在不换根的时候提取出u到 v的路径,实现的方法是基于expose的一种lca。
传统的expose是一直expose到根,另一种做法则是,对于u,v,expose(v),splay(v),这样v到父亲的边打成了重链,然后相应的执行一种类似于expose(u)的操作,但是中止条件改为当u->fa==null的时候就应该结束while,因为u->fa==null说明u和v在同一条重链上,或者说此时u就是lca(u,v),利用lca函数(传指针的引用),最后v和u->ch[1]就是lca到u,v的两个方向的路径。具体可以对比一下expose和lca函数
另外一点是我在debug的时候学习到的,原来的模板里的expose是没有由下往上更新的,也就是说expose(v)之后,v上的所有祖先的信息都是没有更新的,因此expose之后还要splay(v),将信息往上带,但是由于lca函数传的是引用,调用完之后原本的信息就丢失掉了,所以可以在循环里直接upd,把正确的信息往上传。
时间4600ms,差点超时,做这题其实也只是为了学习如何用LCT来操作边权。
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std; #define ll long long
#define maxn 12000
#define NINF -1000000000 struct Edge
{
int u, v, w;
Edge(int ui, int vi, int wi) :u(ui), v(vi), w(wi){}
Edge(){}
}E[maxn * 2], etop; struct Node
{
Node *p, *ch[2];
int val;
int mx;
int size;
bool isRoot;
Node *fa;
Node(){
val = NINF;
size = 0; isRoot = false;
mx = NINF;
}
void setc(Node *c, int d){
ch[d] = c;
c->p = this;
}
bool d(){
return p->ch[1] == this;
}
void upd(){
mx = max(val, max(ch[0]->mx, ch[1]->mx));
}
void relax();
void setRoot(Node *f);
}Tnull, *null = &Tnull; void Node::relax(){ } void Node::setRoot(Node *f){
isRoot = true;
fa = f; p = null;
} Node mem[maxn], *C = mem; Node *make(int v){
C->val = C->mx = v;
C->ch[0] = C->ch[1] = null;
C->isRoot = true;
C->p = null;
C->fa = null;
return C++;
} void rot(Node *t){
Node *p = t->p;
p->relax();
t->relax();
bool d = t->d();
p->p->setc(t, p->d());
p->setc(t->ch[!d], d);
t->setc(p, !d);
p->upd();
if (p->isRoot){
p->isRoot = false;
t->isRoot = true;
t->fa = p->fa;
}
} void pushTo(){ } void splay(Node *u, Node *f = null){
pushTo();
while (u->p != f){
if (u->p->p == f) rot(u);
else u->d() == u->p->d() ? (rot(u->p), rot(u)) : (rot(u), rot(u));
}
u->upd();
} Node *v[maxn];
vector<int> G[maxn];
vector<int> W[maxn];
int n; int nQ; int que[maxn], fa[maxn], qh = 0, qt = 0;
int dep[maxn];
int wht[maxn]; void bfs(){
qh = qt = 0;
que[qt++] = 1;
fa[1] = -1;
while (qh < qt){
int u = que[qh++];
for (int i = 0; i < G[u].size(); i++){
int e = G[u][i];
if (e != fa[u]){
fa[e] = u; v[e]->fa = v[u]; que[qt++] = e;
}
}
}
} Node *expose(Node *u){
Node *v;
for (v = null; u != null; v = u, u = u->fa){
splay(u);
u->ch[1]->setRoot(u);
u->setc(v, 1);
}
return v;
} void dfs(int u, int fa)
{
for (int i = 0; i < G[u].size(); i++){
int v = G[u][i], w = W[u][i];
if (v == fa) continue;
dep[v] = dep[u] + 1;
wht[v] = w;
dfs(v, u);
}
} void lca(Node *&u, Node *&v){
expose(v); splay(v);
for (v = null; u != null; v = u, u = u->fa){
splay(u);
if (u->fa == null) return;
u->ch[1]->setRoot(u);
u->setc(v, 1);
u->upd();
}
} int main()
{
int T; cin >> T;
while (T--)
{
scanf("%d", &n);
memset(dep, 0, sizeof(dep));
for (int i = 0; i <= n; i++) G[i].clear(), W[i].clear();
for (int i = 0; i < n - 1; i++){
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
G[E[i].u].push_back(E[i].v);
G[E[i].v].push_back(E[i].u);
W[E[i].u].push_back(E[i].w);
W[E[i].v].push_back(E[i].w);
}
dep[1] = 1;
dfs(1, -1); wht[1] = NINF;
C = mem;
for (int i = 1; i <= n; i++){
v[i] = make(wht[i]);
}
bfs();
char cmd[10]; int ai, bi;
while (scanf("%s", cmd)){
if (cmd[0] == 'D') break;
scanf("%d%d", &ai, &bi);
if (cmd[0] == 'Q'){
Node *ui = v[ai], *vi = v[bi];
lca(ui, vi);
printf("%d\n", max(ui->ch[1]->mx, vi->mx));
}
else{
--ai;
int ui = E[ai].u, vi = E[ai].v;
if (dep[ui] < dep[vi]) swap(ui, vi);
Node *u = v[ui];
expose(u);
splay(u);
u->val = bi;
splay(u);
}
}
}
return 0;
}
SPOJ375 Query on a tree(LCT边权)的更多相关文章
- SPOJ375 Query on a tree
Description You are given a tree (an acyclic undirected connected graph) with N nodes, and edges num ...
- spoj 375 query on a tree LCT
这道题是树链剖分的裸题,正在学LCT,用LCT写了,发现LCT代码比树链剖分还短点(但我的LCT跑极限数据用的时间大概是kuangbin大神的树链剖分的1.6倍,所以在spoj上是850ms卡过的). ...
- SPOJ375 Query on a tree(树链剖分)
传送门 题意 给出一棵树,每条边都有权值,有两种操作: 把第p条边的权值改为x 询问x,y路径上的权值最大的边 code #include<cstdio> #include<algo ...
- SPOJ375 Query on a tree 【倍增,在线】
题目链接[http://www.spoj.com/problems/QTREE/] 题意:给出一个包含N(N<=10000)节点的无根树,有多次询问,询问的方式有两种1.DIST a b 求a ...
- QTREE5 - Query on a tree V——LCT
QTREE5 - Query on a tree V 动态点分治和动态边分治用Qtree4的做法即可. LCT: 换根后,求子树最浅的白点深度. 但是也可以不换根.类似平常换根的往上g,往下f的拼凑 ...
- SPOJ 375. Query on a tree (动态树)
375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph ...
- QTREE6 - Query on a tree VI 解题报告
QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 动态树(Link Cut Tree) :SPOJ 375 Query on a tree
QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...
随机推荐
- java和python根据对象某一个属性排序
最近在学习java,目前看到java如何对一个对象列表进行排序. 我有一个Member类: public Member(String name,Calendar birthday,Sex gender ...
- ode.js 版本控制 nvm 和 n 使用 及 nvm 重启终端失效的解决方法
今天的话题包括2个部分 node.js 下使用 nvm 或者 n 来进行版本控制 nvm 安装node.js 版本后,重启终端 node , npm 环境变量失效 第一部分 用什么来管理 node.j ...
- SpringMVC综合使用手机管理系统Controller层开发
1. beans.xml的配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=&qu ...
- mysql索引合并:一条sql可以使用多个索引
前言 mysql的索引合并并不是什么新特性.早在mysql5.0版本就已经实现.之所以还写这篇博文,是因为好多人还一直保留着一条sql语句只能使用一个索引的错误观念.本文会通过一些示例来说明如何使用索 ...
- CentOS 7 + nginx + uwsgi + web2py (502 bad gateway nginx)
Web2py开发包中自带的setup-web2py-nginx-uwsgi-centos64.sh脚本, 只能运行在CentOS 6.4中使用, 如果直接在CentOS 7 中使用该脚本布署后, 访问 ...
- 【javascript】html5中使用canvas编写头像上传截取功能
[javascript]html5中使用canvas编写头像上传截取功能 本人对canvas很是喜欢,于是想仿照新浪微博头像上传功能(前端使用canvas) 本程序目前在谷歌浏览器和火狐浏览器测试可用 ...
- SecurityManager一:理解AccessController.doPrivileged()
AccessController.checkPermission()检测模型: 从VM Stack的current stack frame起逐个检测stack frome所指class的protect ...
- RTLviewer与TechnologyMapViewer的区别?
区别: 1.QUARTUS II 中往往要查看RTL Viewer,其实RTLview是编译后的结果,显示的图形都是调用标准单元的结果,这是和思维有关联的显示结果,跟工艺库,FPGA类型,都没有关系: ...
- Actionform
Actionform 2013年7月8日 15:08 Reset 用actionform是把数据恢复到初始状态 Getter/setter Validate 验证 已使用 Microsoft OneN ...
- Java Day 07
构造函数 函数名与类名相同 不用定义返回值类型 没有具体的返回值 作用:给对象初始化值 默认构造函数 如果没有自己定义构造函数,系统会自动生成: 如果定义了,则默认构造函数不会自动生成. 构造函数与一 ...