<题目链接>

题目大意:

给定一棵树,该树带有边权,现在对该树进行三种操作:

一:改变指定编号边的边权;

二:对树上指定路径的边权全部取反;

三:查询树上指定路径的最大边权值。

解题分析:

本题虽然只需要查询某段区间的最大值,但是线段树的每个节点都应该有最大和最小值,因为对区间取反之后,这段区间的最大值的相反数为最小值,最小值的相反数为最大值。然后就是注意对 lazy标记的操作。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
using namespace std;
const int M = 1e5+;
typedef long long ll;
#define INF 1e15
int T,n,pp;
int cnt,tot,head[M],p[M];
int sz[M],son[M],dep[M],f[M],top[M],rnk[M],id[M];
ll a[M];
char s[];
struct edge
{
int v,next;
ll w;
}e[M<<];
struct node
{
ll mx,mn;int lazy;
}tree[M<<];
void init(){
tot=cnt=;memset(head,-,sizeof(head));
}
void add(int u,int v,ll w){
e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];
head[u]=cnt;
}
void fsd(int u,int fa){ //边权转化为点权
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;ll w=e[i].w;
if(v==fa) continue;
a[v]=w;p[(i-)/+]=v;
fsd(v,u);
}
}
void dfs(int u,int fa,int d){
sz[u]=;f[u]=fa;son[u]=-;dep[u]=d;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==fa) continue;
dfs(v,u,d+);
sz[u]+=sz[v];
if(son[u]==-||sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs1(int u,int t){
id[u]=++tot;
rnk[tot]=u;
top[u]=t;
if(son[u]==-) return;
dfs1(son[u],t);
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==f[u]||v==son[u]) continue;
dfs1(v,v);
}
}
void Pushup(int rt){ //维护该点的最大最小值
tree[rt].mx=max(tree[rt<<].mx,tree[rt<<|].mx);
tree[rt].mn=min(tree[rt<<].mn,tree[rt<<|].mn);
}
void Pushdown(int rt){
if(tree[rt].lazy){
int v=tree[rt].lazy;
tree[rt].lazy=;
if(v%==)return; //如果 lazy是偶数,那么就没必要 将lazy 下放,因为对区间进行偶数次取反,相当于没有进行操作 tree[rt<<].mn*=-;tree[rt<<].mx*=-; //将左,右子树的mn,mx取反
tree[rt<<|].mn*=-;tree[rt<<|].mx*=-; swap(tree[rt<<].mn,tree[rt<<].mx); //交换mx,mn
swap(tree[rt<<|].mx,tree[rt<<|].mn);
tree[rt<<].lazy+=v;tree[rt<<|].lazy+=v; //将父节点的lazy传递给子节点
}
}
void build(int l,int r,int rt){
tree[rt].mx=-INF,tree[rt].mn=INF;tree[rt].lazy=; //注意最大最小值都要记录,因为一旦取反,最小值就会变成最大值
if(l==r){
tree[rt].mx=tree[rt].mn=a[rnk[l]];
return;
}
int mid=(l+r)>>;
build(Lson);
build(Rson);
Pushup(rt);
}
void update(int L,int R,int l,int r,int rt){ //线段树上区间修改
if(L<=l&&r<=R){
tree[rt].lazy++; //这里来判断区间数值是否需要取是用 lazy%2 == 1 来判断的
tree[rt].mx*=-;tree[rt].mn*=-; //因为区间取反,所以mx和mn都 *-1
swap(tree[rt].mx,tree[rt].mn); //因为*-1,所以交换最大最小值
return ;
}
Pushdown(rt);
int mid=(l+r)>>;
if(L<=mid) update(L,R,Lson);
if(R>mid) update(L,R,Rson);
Pushup(rt);
}
void change(int l,int r,int rt,int loc,ll v){ //单点修改
if(l==r){
tree[rt].mx=tree[rt].mn=v; //将叶子节点的mx,mn都置为v
return;
}
Pushdown(rt);
int mid=(l+r)>>;
if(loc<=mid) change(Lson,loc,v);
else change(Rson,loc,v);
Pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){ //区间查询最大值
if(L<=l&&r<=R){
return tree[rt].mx;
}
Pushdown(rt);
int mid=(l+r)>>;
ll res=-INF;
if(L<=mid) res=max(res,query(L,R,Lson));
if(R>mid) res=max(res,query(L,R,Rson));
return res;
}
void updates(int x,int y){ //修改树上区间
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>dep[fy]){
update(id[fx],id[x],,n,); //修改线段树上对应区间
x=f[fx],fx=top[x];
}
else{
update(id[fy],id[y],,n,);
y=f[fy],fy=top[y];
}
}
if(x==y) return;
if(dep[x]<dep[y])
update(id[son[x]],id[y],,n,);
else
update(id[son[y]],id[x],,n,);
}
ll sum(int x,int y){ //查询树上区间最大值
int fx=top[x],fy=top[y];ll res=-INF;
while(fx!=fy){
if(dep[fx]>dep[fy]){
res=max(res,query(id[fx],id[x],,n,));
x=f[fx],fx=top[x];
}
else{
res=max(res,query(id[fy],id[y],,n,));
y=f[fy],fy=top[y];
}
}
if(x==y) return res;
if(dep[x]<dep[y])
res=max(res,query(id[son[x]],id[y],,n,));
else
res=max(res,query(id[son[y]],id[x],,n,));
return res;
} int main(){
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
for(int i=;i<n;i++){
int u,v;ll w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);add(v,u,w);
} fsd(,-);a[]=;
dfs(,-,);
dfs1(,);
build(,n,);
while(true){
scanf("%s",s);
if(s[]=='D') break;
if(s[]=='C'){
int a;ll b;
scanf("%d%lld",&a,&b); //单点修改
change(,n,,id[p[a]],b); //线段树上单点修改
}
if(s[]=='N'){
int a,b;
scanf("%d%d",&a,&b);
updates(a,b); //对树上的区间进行修改
}
if(s[]=='Q'){
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",sum(a,b)); //对树上的区间查询
}
}
}
return ;
}

  

2018-09-11

POJ 3237 Tree 【树链剖分】+【线段树】的更多相关文章

  1. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  2. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  3. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  4. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  7. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  8. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  9. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  10. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

随机推荐

  1. easyui combogrid下拉表格的分页/按键/动态搜索

    作者:xfl4629712  <  easyui combogrid下拉表格的分页/按键/动态搜索  > 需求: 1.下拉框下拉时出现表格: 2.表格带分页功能: 3.可以使用向上键.向下 ...

  2. Confluence 6 MBeans

    你可以使用下面的 Confluence MBeans  来实时查看你 Confluence 实例运行的实时信息. CacheStatistics 这个 MBean 显示了 Confluence 有关的 ...

  3. Zookeeper客户端Curator的使用,简单高效

    Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量. 1.引入依赖: ...

  4. checkbox 选中的id拼接长字符串

    需求描述:为了做一个批量操作,需要获取到checkbox选中的项的id,并且把选中的id拼接成字符串. 解决思路:先获取到checkbox选中项,然后拼接.(这tm不废话么),问题的关键就是获取che ...

  5. Python基础之封装

    一.什么是封装 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其 含义是其他程序无法调用. 要了解封装,离不开“私有化”,就是将类或者 ...

  6. 刷《剑指offer》笔记

    本文是刷<剑指offer>代码中的学习笔记,学习ing.. 衡量时间和空间. 递归的代码较为简洁,但性能不如基于循环的实现方法.

  7. mysql 各种关系代数的使用

    连接(JOIN) 选择运算表示为: R⋈S ,其中R和S为不同的两个关系 连接运算是选取两个指定关系中的属性满足给定条件的元祖连接在一起来组成一个新的关系 数学形式: JOIN 关系名1 AND 关系 ...

  8. Visual Studio UML

    1 .类图设计 2.动态图设计,业务工作流程说明了业务为所想服务的业务助教提供了所需要的价值而必须完成的工作,业务用例由一系列的活动组成,它们共同为业务主角生成某些工件,工作流程通常包括一个基本的工作 ...

  9. springboot多环境(dev、test、prod)配置

    propertiest配置格式在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如: ...

  10. 阿里云人脸识别测试接口出错 返回Body:{ "errno": 3002, "err_msg": "ILLEGAL_PARAMETERS", "request_id": "672cba83-cf93-4ef4-9ce5-d87e51601632" }

    错误信息如下 返回Body:{ "errno": 3002, "err_msg": "ILLEGAL_PARAMETERS", ...... ...