题意:给你一棵树,边带权,支持两种操作:修改某条边的权值;查询两点之间的最短路。

lct主要实现单点修改和路径和。

修改x结点的值只需将x Splay到其所在辅助树的根,然后修改其值,再maintain一下即可。

路径和询问要这样做:

我们先 ACCESS(u), 然后在 ACCESS(v) 的过程中, 一旦 走到了包含根结点(也就是包含 u)的 Auxiliary Tree, 这时我们走到的结点恰好就是 u 和 v 的最近公共祖 先, 不妨称这个结点为 d. 这时 d 所在的 Auxiliary Tree 中 d 的右子树的 maxcost 即为 u 到 d 的路径的 最大边权, v 所在的 Auxiliary Tree 的 maxcost 则是 v 到 d 的路径的最大边权. 于是我们所求的答案就是 6 这两个 maxcost 中的最大值. 因为 Access 操作的均摊复杂度为 O(log n), 所以回答这个询问所花时间也 是 O(log n) 的.

Update:换了一种写法,能避免边权的鬼畜问题。即在每条边上添加一个虚点,权值为该边边权;而原先的所有点的点权置为零。这样虽然空间多了一倍,但是非常好处理了!(也即,询问可以用先ChangeRoot,再Access,再Splay,再询问左子树的方法了。)

代码更新在最下方。

<法一>

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
int fa[maxn],c[maxn][2],siz[maxn];
bool is_root[maxn];
int val[maxn],totalval[maxn];
void Maintain(int x)
{
siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;
totalval[x]=totalval[c[x][0]]+totalval[c[x][1]]+val[x];
}
void Rotate(int x,bool flag)
{
int y=fa[x];
c[y][!flag]=c[x][flag];
if(c[x][flag]){
fa[c[x][flag]]=y;
}
if(fa[y] && c[fa[y]][c[fa[y]][1]==y]==y){
c[fa[y]][c[fa[y]][1]==y]=x;
}
fa[x]=fa[y];
c[x][flag]=y;
fa[y]=x;
if(is_root[y]){
is_root[y]=0;
is_root[x]=1;
}
Maintain(y);
Maintain(x);
}
stack<int>st;
void Splay(int x)
{
if(!x || is_root[x]){
return;
}
int y;
while(y=fa[x],(!is_root[x])){
if(is_root[y]){
Rotate(x,c[y][0]==x);
}
else{
if((c[y][0]==x)==(c[fa[y]][0]==y)){
Rotate(y,c[fa[y]][0]==y);
}
else{
Rotate(x,c[y][0]==x);
y=fa[x];
}
Rotate(x,c[y][0]==x);
}
}
Maintain(x);
}
void Spla2(int x)
{
if(!x || is_root[fa[x]]){
return;
}
int y;
while(!is_root[y=fa[x]]){
if(is_root[fa[y]]){
Rotate(x,c[y][0]==x);
}
else{
if((c[y][0]==x)==(c[fa[y]][0]==y)){
Rotate(y,c[fa[y]][0]==y);
}
else{
Rotate(x,c[y][0]==x);
y=fa[x];
}
Rotate(x,c[y][0]==x);
}
}
Maintain(x);
}
void Access(int x){
int y;
Splay(x);
while(fa[x]){
y=fa[x];
Splay(y);
if(c[y][1]){
is_root[c[y][1]]=1;
}
is_root[x]=0;
c[y][1]=x;
Splay(x);
}
if(c[x][1]){
is_root[c[x][1]]=1;
c[x][1]=0;
}
}
int Calc(int x,int y){
if(x==y){
return 0;
}
Splay(y);
if(!fa[y]){
Spla2(x);
return totalval[c[x][0]]+val[x];
}
int z;
while(fa[y]){
z=fa[y];
Splay(z);
if(!fa[z]){
return totalval[c[z][1]]+totalval[y];
}
if(c[z][1]){
is_root[c[z][1]]=1;
}
is_root[y]=0;
c[z][1]=y;
Splay(y);
}
}
int n,m,cur;
int v[maxn<<1],nex[maxn<<1],first[maxn],w[maxn<<1],e;
void AddEdge(int U,int V,int W){
v[++e]=V;
w[e]=W;
nex[e]=first[U];
first[U]=e;
}
int bel[maxn];
bool vis[maxn];
void dfs(int U){
vis[U]=1;
for(int i=first[U];i;i=nex[i]){
if(!vis[v[i]]){
bel[i+1>>1]=v[i];
siz[v[i]]=1;
is_root[v[i]]=1;
val[v[i]]=totalval[v[i]]=w[i];
fa[v[i]]=U;
dfs(v[i]);
}
}
}
int main(){
int op,x,y,z;
// freopen("poj2763.in","r",stdin);
// freopen("poj2763.out","w",stdout);
scanf("%d%d%d",&n,&m,&cur);
for(int i=1;i<n;++i){
scanf("%d%d%d",&x,&y,&z);
AddEdge(x,y,z);
AddEdge(y,x,z);
}
siz[1]=1;
is_root[1]=1;
dfs(1);
for(int i=1;i<=m;++i){
scanf("%d%d",&op,&x);
if(!op){
Access(x);
printf("%d\n",Calc(x,cur));
cur=x;
}
else{
scanf("%d",&y);
Splay(bel[x]);
val[bel[x]]=y;
Maintain(bel[x]);
}
}
return 0;
}

<法二>

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 200005
int fa[maxn],c[maxn][2],siz[maxn];
bool is_root[maxn],delta[maxn];
int val[maxn],totalval[maxn];
void Mark(int x){
if(x){
delta[x]^=1;
}
}
void Maintain(int x)
{
siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;
totalval[x]=totalval[c[x][0]]+totalval[c[x][1]]+val[x];
}
void pushdown(int x){
if(delta[x]){
Mark(c[x][0]);
Mark(c[x][1]);
swap(c[x][0],c[x][1]);
delta[x]=0;
}
}
void Rotate(int x,bool flag)
{
int y=fa[x];
c[y][!flag]=c[x][flag];
if(c[x][flag]){
fa[c[x][flag]]=y;
}
if(fa[y] && c[fa[y]][c[fa[y]][1]==y]==y){
c[fa[y]][c[fa[y]][1]==y]=x;
}
fa[x]=fa[y];
c[x][flag]=y;
fa[y]=x;
if(is_root[y]){
is_root[y]=0;
is_root[x]=1;
}
Maintain(y);
Maintain(x);
}
stack<int>st;
void Splay(int x)
{
pushdown(x);
if(!x || is_root[x]){
return;
}
int U=x;
while(!is_root[U]){
st.push(U);
U=fa[U];
}
st.push(U);
while(!st.empty()){
pushdown(st.top());
st.pop();
}
int y;
while(y=fa[x],(!is_root[x])){
if(is_root[y]){
Rotate(x,c[y][0]==x);
}
else{
if((c[y][0]==x)==(c[fa[y]][0]==y)){
Rotate(y,c[fa[y]][0]==y);
}
else{
Rotate(x,c[y][0]==x);
y=fa[x];
}
Rotate(x,c[y][0]==x);
}
}
Maintain(x);
}
void Access(int x){
int y;
Splay(x);
while(fa[x]){
y=fa[x];
Splay(y);
Splay(x);
if(c[y][1]){
is_root[c[y][1]]=1;
}
is_root[x]=0;
c[y][1]=x;
Splay(x);
}
if(c[x][1]){
is_root[c[x][1]]=1;
c[x][1]=0;
}
}
void ChangeRoot(int x){
Access(x);
Splay(x);
Mark(x);
}
int QSum(int U,int V){
ChangeRoot(U);
Access(V);
Splay(V);
return val[V]+totalval[c[V][0]];
}
int v[maxn<<1],nex[maxn<<1],first[maxn],w[maxn<<1],e;
void AddEdge(int U,int V,int W){
v[++e]=V;
w[e]=W;
nex[e]=first[U];
first[U]=e;
}
int tot,bel[maxn];
void dfs(int U){
for(int i=first[U];i;i=nex[i]){
if(!siz[v[i]]){
bel[i+1>>1]=++tot; siz[tot]=1;
is_root[tot]=1;
val[tot]=totalval[tot]=w[i];
fa[tot]=U; siz[v[i]]=1;
is_root[v[i]]=1;
val[v[i]]=totalval[v[i]]=0;
fa[v[i]]=tot; dfs(v[i]);
}
}
}
int n,m,cur;
int main(){
int op,x,y,z;
// freopen("poj2763.in","r",stdin);
scanf("%d%d%d",&n,&m,&cur);
tot=n;
for(int i=1;i<n;++i){
scanf("%d%d%d",&x,&y,&z);
AddEdge(x,y,z);
AddEdge(y,x,z);
}
siz[1]=1;
is_root[1]=1;
dfs(1);
for(int i=1;i<=m;++i){
scanf("%d%d",&op,&x);
if(!op){
printf("%d\n",QSum(x,cur));
cur=x;
}
else{
scanf("%d",&y);
Splay(bel[x]);
val[bel[x]]=y;
Maintain(bel[x]);
}
}
return 0;
}

【lct】poj2763 Housewife Wind的更多相关文章

  1. POJ2763 Housewife Wind 树链剖分 边权

    POJ2763 Housewife Wind 树链剖分 边权 传送门:http://poj.org/problem?id=2763 题意: n个点的,n-1条边,有边权 修改单边边权 询问 输出 当前 ...

  2. 【BZOJ2049】【LCT】Cave 洞穴勘测

    Description 辉 辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通 道组成,并且每条通道连接了 ...

  3. 【HDU4010】【LCT】Query on The Trees

    Problem Description We have met so many problems on the tree, so today we will have a query problem ...

  4. ZJOI2012网络 题解报告【LCT】

    题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 在这 ...

  5. BZOJ2631 tree 【LCT】

    题目 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的边( ...

  6. POJ2763 Housewife Wind

      Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 9701   Accepted: 2661 Description Aft ...

  7. POJ2763 Housewife Wind(树剖+线段树)

    After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy lif ...

  8. [BZOJ 3669] [Noi2014] 魔法森林 【LCT】

    题目链接:BZOJ - 3669 题目分析 如果确定了带 x 只精灵A,那么我们就是要找一条 1 到 n 的路径,满足只经过 Ai <= x 的边,而且要使经过的边中最大的 Bi 尽量小. 其实 ...

  9. [BZOJ 2594] [Wc2006]水管局长数据加强版 【LCT】

    题目链接:BZOJ - 2594 题目分析 这道题如果没有删边的操作,那么就是 NOIP2013 货车运输,求两点之间的一条路径,使得边权最大的边的边权尽量小. 那么,这条路径就是最小生成树上这两点之 ...

随机推荐

  1. 127.0.0.1、localhost、0.0.0.0的区别

    在开发web应用的测试环境中,如果希望同一个局域网的同事通过内网IP访问自己的应用,则需要把web服务监听的ip地址改为0.0.0.0.为什么用127.0.0.1不行,而用0.0.0.0就可以呢? f ...

  2. Impala笔记之通用命令

    help help命令用于查询其它命令的用法 [quickstart.cloudera:21000] > help select; Executes a SELECT... query, fet ...

  3. nth-child,nth-last-child,only-child,nth-of-type,nth-last-of-type,only-of-type,first-of-type,last-of-type,first-child,last-child伪类区别和用法

    我将这坨伪类分成三组,第一组:nth-child,nth-last-child,only-child第二组:nth-of-type,nth-last-of-type,第三组:first-of-tpye ...

  4. android Timer TimerTask用法笔记

    Android中经常会遇到执行一些周期性定时执行的任务.初学的时候经常会使用Thread.sleep()方法.在android中,有Timer可以专门干这个事情. 先看看Timer.class中都是些 ...

  5. Deep Learning基础--各个损失函数的总结与比较

    损失函数(loss function)是用来估量你模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好.损失函数是经验 ...

  6. 定位、判断、cookie的脚本案例

    Action(){ lr_think_time(20); lr_start_transaction("µã»÷ÊÂÏî°ìÀíÇé¿ö°´Å¥"); web_url("L ...

  7. 《深入理解Java虚拟机》笔记--第三章 、垃圾收集器与内存分配策略

    1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言. Java的垃圾收集(Garbage Collection)主要关注堆和方法区的内存回收. 在GC堆进行回收前,第一件 ...

  8. Jmeter中的逻辑控制器(四)

    Jmeter中的逻辑控制器 (Logic Controller) [线程组]右键—>[添加]—>[逻辑控制器] 简单控制器(Simple Controller ) 没有特殊功能,目的是形成 ...

  9. [重磅]Deep Forest,非神经网络的深度模型,周志华老师最新之作,三十分钟理解!

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 深度学习最大的贡献,个人认为就是表征 ...

  10. Mysql聚合函数count(*) 的性能分析

    你首先要明确的是,在不同的 MySQL 引擎中,count(*) 有不同的实现方式. MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高: 而 ...