POJ 3237 Tree 【树链剖分】+【线段树】
<题目链接>
题目大意:
给定一棵树,该树带有边权,现在对该树进行三种操作:
一:改变指定编号边的边权;
二:对树上指定路径的边权全部取反;
三:查询树上指定路径的最大边权值。
解题分析:
本题虽然只需要查询某段区间的最大值,但是线段树的每个节点都应该有最大和最小值,因为对区间取反之后,这段区间的最大值的相反数为最小值,最小值的相反数为最大值。然后就是注意对 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 【树链剖分】+【线段树】的更多相关文章
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- 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 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- 【CF725G】Messages on a Tree 树链剖分+线段树
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
- 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, ...
- Water Tree CodeForces 343D 树链剖分+线段树
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
随机推荐
- C语言学习及应用笔记之二:C语言static关键字及其使用
C语言有很多关键字,大多关键字使用起来是很明确的,但有一些关键字却要相对复杂一些.我们这里要说明的static关键字就是如此,它的功能很强大,相应的使用也就更复杂. 一般来说static关键字的常见用 ...
- hexo d 部署博客时出错
问题描述: // 第一次遇到的问题 Error: packet_write_wait: Connection to 192.30.253.113 port 22: Broken pipe packet ...
- easyui datagrid 隔行变色
easyui datagrid 隔行变色 一:实现样图 二:实现代码 $('#dataGrid').datagrid({ rowStyler:function(index,row){ if (row ...
- Confluence 6 配置时间和日期格式
你可以修改你 Confluence 为用户显示的时期和时间格式.设置的句法使用的是 SimpleDateFormat class,请参考 Java SimpleDateFormat 文档中的内容来设置 ...
- 新增 修改,对xx名字或者其他属性做校验判断是否存在
需求描述:页面输入完xxName和xx编码,点击提交,根据两项内容做重复校验(就是看看数据库里有木有相同的) 解决思路:把这两个东西作为查询条件去查,查到有记录,提示已存在,就不执行新增或者修改操作. ...
- java内部类和异常类的概念
1.内部类的外嵌类的成员变量在内部类中任然有效,内部类中的方法也可以调用外嵌类中的 方法,内部类中不可以声明类的变量和方法,外嵌的类体可以用内部类声明对象,作为外嵌类的成员.内部类仅供他的外嵌类使用. ...
- @ResponseBody//该注解会将返回值转为json格式并放到响应体中返回到前台
- Python推荐系统库--Surprise理论
Surprise Surprise是scikit系列中的一个.Surprise的User Guide有详细的解释和说明 支持多种推荐算法 基础算法/baseline algorithms 基于近邻方法 ...
- Quartz.NET(任务调度)与Topshelf(服务)的综合使用
http://www.cnblogs.com/jys509/p/4628926.html http://cron.qqe2.com/ Quartz_Topshlf_Demo.7z
- CC攻击原理及防范方法和如何防范CC攻击
一. CC攻击的原理: CC攻击的原理就是攻击者控制某些主机不停地发大量数据包给对方服务器造成服务器资源耗尽,一直到宕机崩溃.CC主要是用来消耗服务器资源的,每个人都有这样的体验:当一个网页访问的人数 ...