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国 ...
随机推荐
- Confluence 6 如何备份和恢复
如何备份 有关备份你数据库使用的命令与你使用的具体数据库有关,例如针对 PostgreSQL 数据库,备份命令为 pg_dump dbname > outfile. 你应该针对你使用的数据库不同 ...
- Java 8 中的 Lambda 表达式
Lambda 表达式是 Java 8 最受欢迎的功能.人们将函数式编程的概念引入了 Java 这门完全面向对象的命令式编程语言. 关于函数式编程是如何运作的,这个话题超出了本文的范围,不过我们会提炼出 ...
- 【深度学习】吴恩达网易公开课练习(class1 week2)
知识点汇总 作业内容:用logistic回归对猫进行分类 numpy知识点: 查看矩阵维度: x.shape 初始化0矩阵: np.zeros((dim1, dim2)) 去掉矩阵中大小是1的维度: ...
- 【linux】复制文件夹内容到另一个文件夹
我一直觉得cp是个非常简单的指令.结果居然遇到坑了.记录一下. 文件夹1:test1/ 文件夹2:test2/ 目标:将test1/中的所有文件和目录拷贝到test2/中 正确指令: cp -rf t ...
- CF939F
好神奇的dp... 首先有一个很简单的思想:设dp[i][j]表示目前到了第i分钟,朝上的面被烤了j分钟的情况下所需的最小交换次数 那么有转移:dp[i][j]=min(dp[i-1][j],dp[i ...
- mybatis初始化过程
mybatis初始化如下: //加载配置文件InputStream resourceAsStream = Resources.getResourceAsStream("testMybatis ...
- jvm(转)
原:https://blog.csdn.net/luomingkui1109/article/details/72820232 1.JVM简析: 作为一名Java使用者,掌握JVM的体系结构 ...
- Java 一个关于使用&&导致的BUG
二维数据track的定义: byte[][] track = new byte[10][10]; 本意:判断track[trackY][trackX]的值是否为零,以及trackX是否小于10. 带B ...
- 即时通讯协议之XMPP
目前IM即时通信有四种协议 1.即时信息和空间协议(IMPP) 2.空间和即时信息协议(PRIM) 3.针对即时通讯和空间平衡扩充的进程开始协议SIP 4.XMPP协议: 该协议的前身是Jabber, ...
- 如何使用Scrapy框架实现网络爬虫
现在用下面这个案例来演示如果爬取安居客上面深圳的租房信息,我们采取这样策略,首先爬取所有租房信息的链接地址,然后再根据爬取的地址获取我们所需要的页面信息.访问次数多了,会被重定向到输入验证码页面,这个 ...