【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2157

【题目大意】

  支持修改边,链上查询最大值最小值总和,以及链上求相反数

【题解】

  树链剖分,然后线段树维护线段操作即可。

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF=~0U>>1;
const int N=20010,M=N<<2;
int a[N];
namespace Segment_Tree{
int tot;
struct node{int l,r,a,b,rev_tag,min_val,max_val,sum;}T[M];
void build(int,int);
void Initialize(int n){
tot=0;
build(1,n);
}
void addtag(int x){
T[x].sum=-T[x].sum;
T[x].max_val=-T[x].max_val;
T[x].min_val=-T[x].min_val;
swap(T[x].min_val,T[x].max_val);
T[x].rev_tag^=1;
}
void pb(int x){
if(T[x].rev_tag){
if(T[x].l)addtag(T[x].l);
if(T[x].r)addtag(T[x].r);
T[x].rev_tag^=1;
}
}
void up(int x){
T[x].sum=T[T[x].l].sum+T[T[x].r].sum;
T[x].max_val=max(T[T[x].l].max_val,T[T[x].r].max_val);
T[x].min_val=min(T[T[x].l].min_val,T[T[x].r].min_val);
}
void build(int l,int r){
int x=++tot;
T[x].a=l;T[x].b=r;T[x].rev_tag=T[x].l=T[x].r=0;
if(l==r){T[x].sum=T[x].min_val=T[x].max_val=a[l];return;}
int mid=(l+r)>>1;
T[x].l=tot+1;build(l,mid);
T[x].r=tot+1;build(mid+1,r);
up(x);
}
void change(int x,int pos,int p){
if(T[x].a==T[x].b){T[x].sum=T[x].min_val=T[x].max_val=p;return;}
if(T[x].rev_tag)pb(x);
int mid=(T[x].a+T[x].b)>>1;
if(mid>=pos&&T[x].l)change(T[x].l,pos,p);
if(mid<pos&&T[x].r)change(T[x].r,pos,p);
up(x);
}
void reverse(int x,int a,int b){
if(a<=T[x].a&&T[x].b<=b){addtag(x);return;}
if(T[x].rev_tag)pb(x); int mid=(T[x].a+T[x].b)>>1;
if(a<=mid)reverse(T[x].l,a,b);
if(b>mid)reverse(T[x].r,a,b);
up(x);
}
int query_sum(int x,int a,int b){
if(a<=T[x].a&&T[x].b<=b)return T[x].sum;
if(T[x].rev_tag)pb(x); int mid=(T[x].a+T[x].b)>>1,res=0;
if(a<=mid)res+=query_sum(T[x].l,a,b);
if(b>mid)res+=query_sum(T[x].r,a,b);
return res;
}
int query_min(int x,int a,int b){
//printf("%d %d %d\n",T[x].min_val,a,b);
if(a<=T[x].a&&T[x].b<=b)return T[x].min_val;
if(T[x].rev_tag)pb(x); int mid=(T[x].a+T[x].b)>>1,res=INF;
if(a<=mid)res=min(res,query_min(T[x].l,a,b));
if(b>mid)res=min(res,query_min(T[x].r,a,b));
return res;
}
int query_max(int x,int a,int b){
if(a<=T[x].a&&T[x].b<=b)return T[x].max_val;
if(T[x].rev_tag)pb(x); int mid=(T[x].a+T[x].b)>>1,res=-INF;
if(a<=mid)res=max(res,query_max(T[x].l,a,b));
if(b>mid)res=max(res,query_max(T[x].r,a,b));
return res;
}
}
namespace Tree_Chain_Subdivision{
int ed,root,d[N],v[N<<1],vis[N],f[N],g[N<<1];
int nxt[N<<1],size[N],son[N],st[N],en[N],dfn,top[N];
void add_edge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x,d[v[i]]=d[x]+1;
dfs(v[i]),size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
if(x==-1)return;
st[x]=++dfn;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
en[x]=dfn;
}
// 查询x,y两点的lca
int lca(int x,int y){
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
return d[x]<d[y]?x:y;
}
// x是y的祖先,查询x到y方向的第一个点
int lca2(int x,int y){
int t;
while(top[x]!=top[y])t=top[y],y=f[top[y]];
return x==y?t:son[x];
}
// 对x到y路径上的点取反操作
void reverse(int x,int y){
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
Segment_Tree::reverse(1,st[top[x]],st[x]);
}if(d[x]<d[y]){int z=x;x=y;y=z;}
Segment_Tree::reverse(1,st[y]+1,st[x]);
}
// 查询x到y路径上的最小值
int query_min(int x,int y){
int res=INF;
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
res=min(res,Segment_Tree::query_min(1,st[top[x]],st[x]));
}if(d[x]<d[y]){int z=x;x=y;y=z;}
res=min(res,Segment_Tree::query_min(1,st[y]+1,st[x]));
return res;
}
// 查询x到y路径上的最大值
int query_max(int x,int y){
int res=-INF;
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
res=max(res,Segment_Tree::query_max(1,st[top[x]],st[x]));
}if(d[x]<d[y]){int z=x;x=y;y=z;}
res=max(res,Segment_Tree::query_max(1,st[y]+1,st[x]));
return res;
}
// 查询x到y路径上的总和
int query_sum(int x,int y){
int res=0;
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
res=res+Segment_Tree::query_sum(1,st[top[x]],st[x]);
}if(d[x]<d[y]){int z=x;x=y;y=z;}
res=res+Segment_Tree::query_sum(1,st[y]+1,st[x]);
return res;
}
void Initialize(){
memset(g,dfn=ed=0,sizeof(g));
memset(v,0,sizeof(v));
memset(nxt,0,sizeof(nxt));
memset(son,-1,sizeof(son));
}
}
int n,m,e[N][3];
char op[5];
int main(){
scanf("%d",&n);
using namespace Tree_Chain_Subdivision;
Initialize();
for(int i=0;i<n-1;i++){
scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
e[i][0]++; e[i][1]++;
add_edge(e[i][0],e[i][1]);
add_edge(e[i][1],e[i][0]);
}dfs(1);dfs2(1,1);
for(int i=0;i<n-1;i++){
if(d[e[i][0]]>d[e[i][1]])swap(e[i][0],e[i][1]);
a[st[e[i][1]]]=e[i][2];
}
Segment_Tree::Initialize(n);
scanf("%d",&m);
while(m--){
scanf("%s",op);
if(op[0]=='C'){
int x,y;
scanf("%d%d",&x,&y);
Segment_Tree::change(1,st[e[x-1][1]],y);
}
else if(op[0]=='N'){
int x,y;
scanf("%d%d",&x,&y);
Tree_Chain_Subdivision::reverse(x+1,y+1);
}
else if(op[0]=='S'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",Tree_Chain_Subdivision::query_sum(x+1,y+1));
}
else if(op[1]=='I'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",Tree_Chain_Subdivision::query_min(x+1,y+1));
}
else{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",Tree_Chain_Subdivision::query_max(x+1,y+1));
}
}return 0;
}

BZOJ 2157 旅游(树链剖分+线段树)的更多相关文章

  1. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  2. BZOJ2157旅游——树链剖分+线段树

    题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...

  3. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  4. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  5. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  6. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

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

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

  9. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  10. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

随机推荐

  1. niceScroll 简单使用 及 插件API

    官方网址[https://nicescroll.areaaperta.com/]  注:效果见官网右侧滚动条 jquery.nicescroll文件下载地址 引入核心文件,插件需要引入1.5.X以上版 ...

  2. Android控件——监听按钮的点击事件

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAroAAAFTCAIAAABZPDiZAAAgAElEQVR4nOy9918UWfb///1jdu2uBs

  3. mssql手工注入2

    --+ 先说一些函数的说明: substring(str,start,len) 截取字符串的作用,第一个参数为要截取的字符串,第二个参数为从哪里开始截取,第三个参数为截取的长度 ascii(char) ...

  4. python基础===通过菲波那契数列,理解函数

    def fib(n): # write Fibonacci series up to n """Print a Fibonacci series up to n.&quo ...

  5. linux dpm机制分析(上)【转】

    转自:http://blog.csdn.net/lixiaojie1012/article/details/23707681 1      DPM介绍 1.1        Dpm:  设备电源管理, ...

  6. javascript反混淆之packed混淆

    function getKey() { var aaaafun = function(p, a, c, k, e, d) { e = function(c) { return (c < a ? ...

  7. [收集]关于MSSQL数据库的一些查询

    sqlserver快速查找所有存储过程中是否包含某字符 --将XXXX替换成你要查找的内容 select name from sysobjects o, syscomments s where o.i ...

  8. jquery - 实例1

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="text2.aspx.cs& ...

  9. 15:django 缓存架构

    动态网站的一个基本权衡就是他们是动态的,每次一个用户请求一个页面,web服务器进行各种各样的计算-从数据库查询到模板渲染到业务逻辑-从而生成站点访问者看到的页面.从处理开销的角度来看,相比标准的从文件 ...

  10. hrbust - 2239

    影子模仿术 Time Limit: 500 MS Memory Limit: 32768 K Total Submit: 7(5 users) Total Accepted: 2(2 users) R ...