cogs1583. [POJ3237]树的维护
1583. [POJ3237]树的维护
http://www.cogs.pro/cogs/problem/problem.php?pid=1583
★★★☆ 输入文件:maintaintree.in
输出文件:maintaintree.out
简单对比
时间限制:5 s 内存限制:128 MB
【题目描述】
给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
CHANGE i v:将第i条边的权值改成v。
NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
QUERY a b:找出点a到点b路径上各边的最大权值。
【输入格式】
输入文件的第一行有一个整数N(N<=10000)。
接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。
接下来是若干条指令(不超过10^5条),都按照上面所说的格式。
输入文件的最后一行是"DONE".
【输出格式】
对每个“QUERY”指令,输出一行,即路径上各边的最大权值。
【样例输入】
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
【样例输出】
1
3
【提示】
这里的输入输出格式和POJ上原题略有不同。
【来源】
难点在于取相反数操作
记录下最大值和最小值,有取相反数操作时,就把两个值变成相反数,再交换两数的值就ok,然后给这个区间打上标记(线段树的lazy标记),以后访问或更改值时记得下传标记就好。
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std; const int MAXN = ;
struct Edge{
int to,next;
}edge[MAXN*];
int head[MAXN],tot;
int top[MAXN];//top[v]表示v所在的重链的顶端节点
int fa[MAXN]; //父亲节点
int deep[MAXN];//深度
int num[MAXN];//num[v]表示以v为根的子树的节点数
int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置
int fp[MAXN];//和p数组相反
int son[MAXN];//重儿子
int pos;
void init(){
tot = ;
memset(head,-,sizeof(head));
pos = ;
memset(son,-,sizeof(son));
}
void addedge(int u,int v){
edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
}
void dfs1(int u,int v,int d){
deep[v]=d;
fa[v]=u;
num[v]=;
for(int i=head[v];i!=-;i=edge[i].next){
int to=edge[i].to;
if(to==u)continue;
dfs1(v,to,d+);
num[v]+=num[to];
if(son[v]==-||num[son[v]]<num[to])son[v]=to;
}
}
void dfs2(int u,int v){
top[u]=v;
p[u]=pos++;
if(son[u]==-)return;
dfs2(son[u],v);
for(int i=head[u];i!=-;i=edge[i].next){
int to=edge[i].to;
if(to==fa[u]||to==son[u])continue;
dfs2(to,to);
}
} //线段树
struct Node{
int l,r;
int Max;
int Min;
int ne;
}tr[MAXN*];
void build(int i,int l,int r){
tr[i].l = l;
tr[i].r = r;
tr[i].Max = ;
tr[i].Min = ;
tr[i].ne = ;
if(l == r)return;
int mid = (l+r)/;
build(i<<,l,mid);
build((i<<)|,mid+,r);
}
void push_up(int i)
{
tr[i].Max = max(tr[i<<].Max,tr[(i<<)|].Max);
tr[i].Min = min(tr[i<<].Min,tr[(i<<)|].Min);
}
void push_down(int i){ if(tr[i].l == tr[i].r)return;
if(tr[i].ne)
{
tr[i<<].Max = -tr[i<<].Max;
tr[i<<].Min = -tr[i<<].Min;
swap(tr[i<<].Min,tr[i<<].Max);
tr[(i<<)|].Max = -tr[(i<<)|].Max;
tr[(i<<)|].Min = -tr[(i<<)|].Min;
swap(tr[(i<<)|].Max,tr[(i<<)|].Min);
tr[i<<].ne ^= ;
tr[(i<<)|].ne ^= ;
tr[i].ne = ;
}
}
void update(int i,int k,int val){ // 更新线段树的第k个值为val if(tr[i].l == k && tr[i].r == k)
{
tr[i].Max = val;
tr[i].Min = val;
tr[i].ne = ;
return;
}
push_down(i);
int mid = (tr[i].l + tr[i].r)/;
if(k <= mid)update(i<<,k,val);
else update((i<<)|,k,val);
push_up(i);
} void ne_update(int i,int l,int r){
if(tr[i].l==l&&tr[i].r==r){
tr[i].Max=-tr[i].Max;tr[i].Min=-tr[i].Min;
swap(tr[i].Max,tr[i].Min);
tr[i].ne^=;return;
}
push_down(i);
int mid=(tr[i].l+tr[i].r)>>;
if(r<=mid)ne_update(i<<,l,r);
else if(l>mid)ne_update((i<<)|,l,r);
else ne_update(i<<,l,mid),ne_update((i<<)|,mid+,r);
tr[i].Min=min(tr[i<<].Min,tr[(i<<)|].Min);
tr[i].Max=max(tr[i<<].Max,tr[(i<<)|].Max);
}
int query(int i,int l,int r){ //查询线段树中[l,r] 的最大值 if(tr[i].l == l && tr[i].r == r)
return tr[i].Max;
push_down(i);
int mid = (tr[i].l + tr[i].r)/;
if(r <= mid)return query(i<<,l,r);
else if(l > mid)return query((i<<)|,l,r);
else return max(query(i<<,l,mid),query((i<<)|,mid+,r));
push_up(i);
}
int findmax(int u,int v){//查询u->v边的最大值 int f1 = top[u], f2 = top[v];
int tmp = -;
while(f1 != f2)
{
if(deep[f1] < deep[f2])
{
swap(f1,f2);
swap(u,v);
}
tmp = max(tmp,query(,p[f1],p[u]));
u = fa[f1]; f1 = top[u];
}
if(u == v)return tmp;
if(deep[u] > deep[v]) swap(u,v);
return max(tmp,query(,p[son[u]],p[v]));
}
void Negate(int u,int v){
int f1=top[u],f2=top[v];
while(f1!=f2){
if(deep[f1]<deep[f2])swap(f1,f2),swap(u,v);
ne_update(,p[f1],p[u]);
u=fa[f1];f1=top[u];
}
if(u==v)return;
if(deep[u]>deep[v])swap(u,v);
ne_update(,p[son[u]],p[v]);
return;
}
int E[MAXN][];
int main()
{
//freopen("Cola.txt","r",stdin);
freopen("maintaintree.in","r",stdin);
freopen("maintaintree.out","w",stdout);
int T,n;
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][]);
addedge(E[i][],E[i][]);
}
dfs1(,,);
dfs2(,);
build(,,pos-);
for(int i=;i<n-;i++){
if(deep[E[i][]]>deep[E[i][]])swap(E[i][],E[i][]);
update(,p[E[i][]],E[i][]);
}
char ch[];
int u,v;
while(){
scanf("%s",ch);
if(ch[]=='D')break;
scanf("%d%d",&u,&v);
if(ch[]=='Q')printf("%d\n",findmax(u,v));
else if(ch[]=='C')update(,p[E[u-][]],v);
else Negate(u,v);
}
}
return ;
}
cogs1583. [POJ3237]树的维护的更多相关文章
- Cogs 1583. [POJ3237]树的维护 LCT,树链剖分
题目:http://cojs.tk/cogs/problem/problem.php?pid=1583 1583. [POJ3237]树的维护 ★★★☆ 输入文件:maintaintree.in ...
- COGS 1583. [POJ3237]树的维护
二次联通门 : COGS 1583. [POJ3237]树的维护 /* COGS 1583. [POJ3237]树的维护 树链剖分 + 边权化点权 线段树 单点修改 + 区间取相反数 + 查询区间最大 ...
- poj3237 树链部分 边权模板
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7384 Accepted: 2001 Description ...
- 【bzoj3533】[Sdoi2014]向量集 线段树+STL-vector维护凸包
题目描述 维护一个向量集合,在线支持以下操作:"A x y (|x|,|y| < =10^8)":加入向量(x,y);"Q x y l r (|x|,|y| < ...
- hdu 1556 Color the ball(线段树区间维护+单点求值)
传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/3276 ...
- cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树
1583. [POJ 3237] 树的维护 ★★★★ 输入文件:maintaintree.in 输出文件:maintaintree.out 简单对比时间限制:5 s 内存限制:128 ...
- 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- CodeForces 587 E.Duff as a Queen 线段树动态维护区间线性基
https://codeforces.com/contest/587/problem/E 一个序列, 1区间异或操作 2查询区间子集异或种类数 题解 解题思路大同小异,都是利用异或的性质进行转化,st ...
随机推荐
- jquery .html(),.text(),.val()用法
.html()用为读取和修改元素的HTML标签 .text()用来读取或修改元素的纯文本内容 .val()用来读取或修改表单元素的value值. 这三个方法功能上的对比 .html(),.text() ...
- 《C prime plus (第五版)》 ---第11章 字符串和字符串函数---3
字符串函数总结: 下面是头文件 string.h 中定义的函数: 序号 函数 & 描述 1 void *memchr(const void *str, int c, size_t n)在参数 ...
- 1.1 BASIC PROGRAMMING MODEL(算法 Algorithms 第4版)
1.1.1 private static void exercise111() { StdOut.println("1.1.1:"); StdOut.println((0+15)/ ...
- Mysql转换表存储引擎的三种方式
或许会有一些场景需要改变表的存储引擎,例如存储日志的表如果几乎只有insert和少量的select操作,为了追求更好的插入性能有可能会需要把存储引擎更换为MyISAM.但是,本文不建议在同一个数据库中 ...
- python注释行与段落
注释行:# 注释段:‘’‘ ’‘’
- j2ee项目Java代码性能优化要点(抄书)
亚信联创科技出版的. 1.与log4j有关的性能问题 Logger对象的标准定义方式: private static transient Logger log=Logger.getLogger(cre ...
- linux命令学习笔记:cut详解
cut命令从文件的每一行剪切字节.字符和字段并将它们写至标准输出.它是以文件的每一行作为处理对象的. 命令格式:cut [选项] [范围] 文件.选项用来指定单位(字节.字符还是字段),范围指定选项的 ...
- CodeForces - 1000E :We Need More Bosses(无向图缩点+树的直径)
Your friend is developing a computer game. He has already decided how the game world should look lik ...
- Python 2.7获取网站源代码的几种方式_20160924
#coding:utf-8 import urllib2,cookielib if __name__ == '__main__': root_url='https://www.baidu.com/' ...
- ACM学习历程——POJ 1700 Crossing River(贪心)
Description A group of N people wishes to go across a river with only one boat, which can at most ca ...