●POJ 3237 Tree
题链:
http://poj.org/problem?id=3237
题解:
LCT
说一说如何完成询问操作就好了(把一条链的边权变成相反数的操作可以类比着来):
首先明确一下,我们把边权下放到点上。
(由于不存在合并,即不需要MovetoRoot操作,也就是说不需要改变树的形态,让它成为以1为根的有根树即可)
对于询问的a,b之间链上的最大值,
我们首先调用Access(b)函数,让b和根之间形成一条重链,
然后对x=a执行类似Access的过程,直到某一刻发现fa[x]==0时,
则表明现在的x是在b到根的路径上,或者说,此时的x点是a,b的最近公共祖先lca,
所以直接返回y子树和ch[x][1]子树的最大值就好了。
建议结合代码理解:
int Query(int x,int y){
static int ret; Access(y);
for(y=0;x;y=x,x=fa[x]){
Splay(x);
if(fa[x]) ch[x][1]=y;
else ret=max(maxi[y],maxi[ch[x][1]]);
Pushup(x);
}
return ret;
}
其他就没什么好说的了,都比较常规。
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 10050
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
int to[MAXN*2],nxt[MAXN*2],val[MAXN*2],head[MAXN],ent;
void Reset(){ent=2; memset(head,0,sizeof(head));}
void Adde(int u,int v,int w){
to[ent]=v; val[ent]=w;
nxt[ent]=head[u]; head[u]=ent++;
}
}E;
int belong[MAXN];
int Case,N;
struct LCT{
int ch[MAXN][2],fa[MAXN];
int maxi[MAXN],mini[MAXN],w[MAXN],lazy[MAXN];
void Reset(){
memset(ch,0,sizeof(ch));
memset(lazy,0,sizeof(lazy));
maxi[0]=-INF; mini[0]=INF;
}
bool Which(int x){return ch[fa[x]][1]==x;}
bool Isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void Pushup(int x){
maxi[x]=max(w[x],max(maxi[ch[x][0]],maxi[ch[x][1]]));
mini[x]=min(w[x],min(mini[ch[x][0]],mini[ch[x][1]]));
}
void Opposite(int x){ w[x]*=-1; maxi[x]*=-1; mini[x]*=-1;
swap(maxi[x],mini[x]);
lazy[x]^=1;
}
void Pushdown(int x){
if(!Isroot(x)) Pushdown(fa[x]);
if(!lazy[x]) return;
Opposite(ch[x][0]); Opposite(ch[x][1]);
lazy[x]^=1;
}
void Rotate(int x){
static int y,z,l1,l2;
y=fa[x]; z=fa[y];
l1=Which(x); l2=Which(y); fa[x]=z;
if(!Isroot(y)) ch[z][l2]=x;
fa[ch[x][l1^1]]=y; fa[y]=x;
ch[y][l1]=ch[x][l1^1]; ch[x][l1^1]=y;
Pushup(y);
}
void Splay(int x){
static int y; Pushdown(x);
for(;y=fa[x],!Isroot(x);Rotate(x))
if(!Isroot(y)) Rotate(Which(x)==Which(y)?y:x);
Pushup(x);
}
void Access(int x){
static int y;
for(y=0;x;y=x,x=fa[x])
Splay(x),ch[x][1]=y,Pushup(x);
}
void Change(int i,int v){
static int x; x=belong[i];
Splay(x); w[x]=v; Pushup(x);
}
void Negate(int x,int y){
Access(y);
for(y=0;x;y=x,x=fa[x]){
Splay(x);
if(fa[x]) ch[x][1]=y;
else Opposite(y),Opposite(ch[x][1]);
Pushup(x);
}
}
int Query(int x,int y){
static int ret; Access(y);
for(y=0;x;y=x,x=fa[x]){
Splay(x);
if(fa[x]) ch[x][1]=y;
else ret=max(maxi[y],maxi[ch[x][1]]);
Pushup(x);
}
return ret;
}
}DT;
void DFS(int u,int dad){
DT.fa[u]=dad;
for(int i=E.head[u];i;i=E.nxt[i]){
int v=E.to[i]; if(v==dad) continue;
belong[i>>1]=v; DT.maxi[v]=DT.mini[v]=DT.w[v]=E.val[i];
DFS(v,u);
}
}
int main(){
int a,b,c; char cmd[10];
for(scanf("%d",&Case);Case;Case--){
DT.Reset(); E.Reset();
scanf("%d",&N);
for(int i=1;i<N;i++){
scanf("%d%d%d",&a,&b,&c);
E.Adde(a,b,c); E.Adde(b,a,c);
}
DFS(1,0);
while(~scanf("%s",cmd)){
if(cmd[0]=='D') break;
scanf("%d%d",&a,&b);
if(cmd[0]=='Q') printf("%d\n",DT.Query(a,b));
else if(cmd[0]=='C') DT.Change(a,b);
else DT.Negate(a,b);
}
}
return 0;
}
●POJ 3237 Tree的更多相关文章
- poj 3237 Tree [LCA] (树链剖分)
poj 3237 tree inline : 1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高. 2. 很明显,类 ...
- poj 3237 Tree(树链拆分)
题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询a ...
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
- 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: 7268 Accepted: 1969 Description ...
- POJ 3237 Tree (树链剖分)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 2825 Accepted: 769 Description ...
- 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 【树链剖分】+【线段树】
<题目链接> 题目大意: 给定一棵树,该树带有边权,现在对该树进行三种操作: 一:改变指定编号边的边权: 二:对树上指定路径的边权全部取反: 三:查询树上指定路径的最大边权值. 解题分析: ...
随机推荐
- Bate敏捷冲刺每日报告--day2
1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285) Git链接:https://github.com/WHUSE2017/C-team 2 ...
- Linux下进程间通信--共享内存:最快的进程间通信方式
共享内存: 一.概念: 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间. 进程A可以即时看到进程B ...
- Oracle数据库游标精解
游标 定义:标识结果集中数据行的一种容器(CURSOR),游标允许应用程序对查询语句返回的行结果集中的每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作.实际上是一种能从包括多条数据记录 ...
- hadoop大数据技术架构详解
大数据的时代已经来了,信息的爆炸式增长使得越来越多的行业面临这大量数据需要存储和分析的挑战.Hadoop作为一个开源的分布式并行处理平台,以其高拓展.高效率.高可靠等优点越来越受到欢迎.这同时也带动了 ...
- vue-cli webpack3扩展多模块打包
场景 在实际的项目开发中会出现这样的场景,项目中需要多个模块(单页或者多页应用)配合使用的情况,而vue-cli默认只提供了单入口打包,所以就想到对vue-cli进行扩展 实现 首先得知道webpac ...
- Map集合、散列表、红黑树介绍
前言 声明,本文用得是jdk1.8 前面已经讲了Collection的总览和剖析List集合: Collection总览 List集合就这么简单[源码剖析] 原本我是打算继续将Collection下的 ...
- Python入门之函数的装饰器
本章目录: 装饰器: 一.为什么要用装饰器 二.什么是装饰器 三.无参装饰器 四.装饰器语法糖 五.认证装饰器实现 六.叠加多个装饰器 七.带参装饰器 ======================== ...
- Java面向对象之封装 入门实例(一)
一.基础概念 (一)面向对象的三大特征: 1.封装 2.继承 3.多态 (二)封装:隐藏实现细节,对外提供公共的访问方式(接口). 封装的体现之一:将属性都 ...
- javascript实现图片延迟加载方法汇总(三种方法)
看到一些大型网站,页面如果有很多图片的时候,当你滚动到相应的行时,当前行的图片才即时加载的,这样子的话页面在打开只加可视区域的图片,而其它隐藏的图片则不加载,一定程序上加快了页面加载的速度,跟着小编一 ...
- DVA框架统一处理所有页面的loading状态
dva 有一个管理 effects 执行的 hook,并基于此封装了 dva-loading 插件.通过这个插件,我们可以不必一遍遍地写 showLoading 和 hideLoading,当发起请求 ...