POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - POJ3237
题意概括
Description
给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
CHANGE i v:将第i条边的权值改成v。
NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
QUERY a b:找出点a到点b路径上各边的最大权值。
Input
多组数据,数据为T<=20,对于每组数据:
第一行有一个整数N(N<=10000)。
接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。
接下来是若干条指令(不超过10^5条),都按照上面所说的格式。
最后一行是"DONE".
Output
对每个“QUERY”指令,输出一行,即路径上各边的最大权值。
Sample Input
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
题解
树链剖分+线段树单点修改、区间修改、区间询问。
对于取相反数的,我们只需要维护一个最大值,一个最小值,然后打一下懒标记就可以了。
在下传的时候,最大值反一反一定是最小的,最小值反一反一定是最大的,然后就好办了。
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N=10005;
struct Edge{
int cnt,y[N*2],z[N*2],nxt[N*2],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
struct edge{
int a,b,c;
}e[N];
int T,n,fa[N],size[N],fadis[N],depth[N],son[N],top[N],p[N],ap[N],cnp;
struct Tree{
int ma,mi,add;
}t[N*4];
void Get_Gen_Info(int rt,int pre,int d){
depth[rt]=d,fa[rt]=pre,size[rt]=1,son[rt]=-1;
for (int i=g.fst[rt];i;i=g.nxt[i])
if (g.y[i]!=pre){
int s=g.y[i];
Get_Gen_Info(s,rt,d+1);
fadis[s]=g.z[i];
size[rt]+=size[s];
if (son[rt]==-1||size[s]>size[son[rt]])
son[rt]=s;
}
}
void Get_Pos(int rt,int tp){
top[rt]=tp,p[rt]=++cnp,ap[cnp]=rt;
if (son[rt]==-1)
return;
else
Get_Pos(son[rt],tp);
for (int i=g.fst[rt];i;i=g.nxt[i]){
int s=g.y[i];
if (s!=fa[rt]&&s!=son[rt])
Get_Pos(s,s);
}
}
void pushup(int rt){
int ls=rt<<1,rs=ls|1;
t[rt].mi=min(t[ls].mi,t[rs].mi);
t[rt].ma=max(t[ls].ma,t[rs].ma);
}
void build(int rt,int le,int ri){
t[rt].add=0;
if (le==ri){
t[rt].ma=t[rt].mi=fadis[ap[le]];
return;
}
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
build(ls,le,mid);
build(rs,mid+1,ri);
pushup(rt);
}
void fz(int &x,int &y){
x=-x,y=-y;
swap(x,y);
}
void pushdown(int rt){
int &a=t[rt].add;
int ls=rt<<1,rs=ls|1;
if (a==0)
return;
t[ls].add^=1,t[rs].add^=1;
fz(t[ls].ma,t[ls].mi);
fz(t[rs].ma,t[rs].mi);
a=0;
}
void change(int rt,int le,int ri,int pos,int v){
if (le==ri){
t[rt].mi=t[rt].ma=v;
return;
}
pushdown(rt);
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
if (pos<=mid)
change(ls,le,mid,pos,v);
else
change(rs,mid+1,ri,pos,v);
pushup(rt);
}
void update(int rt,int le,int ri,int xle,int xri){
if (le>xri||ri<xle)
return;
if (xle<=le&&ri<=xri){
t[rt].add^=1;
fz(t[rt].ma,t[rt].mi);
return;
}
pushdown(rt);
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
update(ls,le,mid,xle,xri);
update(rs,mid+1,ri,xle,xri);
pushup(rt);
}
int query(int rt,int le,int ri,int xle,int xri){
if (le>xri||ri<xle)
return -1e9;
if (xle<=le&&ri<=xri)
return t[rt].ma;
pushdown(rt);
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
return max(query(ls,le,mid,xle,xri),query(rs,mid+1,ri,xle,xri));
}
void fupdate(int a,int b){
int f1=top[a],f2=top[b];
while (f1!=f2){
if (depth[f1]<depth[f2])
swap(f1,f2),swap(a,b);
update(1,1,n,p[f1],p[a]);
a=fa[f1],f1=top[a];
}
if (a==b)
return;
if (depth[a]>depth[b])
swap(a,b);
update(1,1,n,p[son[a]],p[b]);
}
int find(int a,int b){
int f1=top[a],f2=top[b],ans=-1e9;
while (f1!=f2){
if (depth[f1]<depth[f2])
swap(f1,f2),swap(a,b);
ans=max(ans,query(1,1,n,p[f1],p[a]));
a=fa[f1],f1=top[a];
}
if (a==b)
return ans;
if (depth[a]>depth[b])
swap(a,b);
return max(ans,query(1,1,n,p[son[a]],p[b]));
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%d",&n);
g.clear();
for (int i=1,a,b,c;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
g.add(a,b,c);
g.add(b,a,c);
e[i].a=a,e[i].b=b,e[i].c=c;
}
cnp=0,fadis[1]=0;
Get_Gen_Info(1,0,0);
Get_Pos(1,1);
build(1,1,n);
for (int i=1;i<n;i++)
if (depth[e[i].a]>depth[e[i].b])
swap(e[i].a,e[i].b);
char str[10];
int a,b;
while (scanf("%s",str)&&str[0]!='D'){
scanf("%d%d",&a,&b);
if (str[0]=='C')
change(1,1,n,p[e[a].b],b);
else if (str[0]=='N')
fupdate(a,b);
else
printf("%d\n",find(a,b));
}
}
return 0;
}
POJ3237 Tree 树链剖分 线段树的更多相关文章
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- 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 ...
- 【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 ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
随机推荐
- Keil4 几例异常解决办法
以下几个问题在Keil5上没有发现,不过因为下载的例子都是Keil4,强迫症让我用起了Keil4 错误一:main.c: Warning: C3910W: Old syntax, please use ...
- C++常量 运算符
\n 换行 光标移到下一行 \0 空值 \t 水平制表符 \r 回车 光标回到本行开头 ...
- luogu P2627 修剪草坪
传送门 单调队列优化dp板子 表示不大想写详细做法,自己看代码吧qwq (懒) 注意细节,不然就会跟我一样WA4次 // luogu-judger-enable-o2 #include<bits ...
- day1 查看当前目录命令:pwd
用到查看当前目录的完整路径使用:pwd 物理路径和连接路径什么鬼?没明白暂时借鉴别人的记录下 显示当前目录的物理路径 pwd –P 1: [root@DB-Server init.d]# cd /et ...
- Java 学习札记(三)免安装版TomCat中tomcat6w.exe的运行
1.使用环境 很多时候我们用的是官网的解压免安装版的Tomcat,相比安装Tomcat除了少了安装步骤以外还少了tomcat6w.exe运行所需要的环境变量,所以一般Java开发免安装版的已经足够使用 ...
- 第三周结对项目--小学生四则运算CAI软件汇报及总结(UI/web)
前言: 这周是和我队友苏卫喜一起结对开发,我主要是写项目文档需求分析,她是通过我的需求文档来进行做思维导图,之后我们通过思维导图一起讨论用户界面设计. 以下就是我的需求分析1.0版本 1. 软件名 ...
- python - json/pickle
# import json #将数据类型转换成字符串 # data = {"a":"123"} # a = json.dumps(data) # print(a ...
- swift学习第一天---常量变量基础数据类型
import Foundation /** * 1.常量 变量 知识要点:常量的定义用let 变量的定义用var 常量一旦定义便不可再更改. 变量定义之后可以在定义之后的程序中任意地方进行修改. */ ...
- java 两个list 交集 并集 差集 去重复并集
前提需要明白List是引用类型,引用类型采用引用传递. 我们经常会遇到一些需求求集合的交集.差集.并集.例如下面两个集合: List<String> list1 = new ArrayLi ...
- FarBox的建站过程
FarBox的建站过程 本文转自:http://mosir.org/html/y2012/How-to-build-your-website-by-farbox.html 作者: mosir 时间: ...