题目

Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

输入格式

输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0…N − 1。接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1…N − 1。|w| <= 1000。输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。接下来有M 行,每行描述了一个操作,操作有如下五种形式: C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。 N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。 SUM u v,表示询问从景点u 到v 所获得的总愉悦度。 MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。 MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。

输出格式

对于每一个询问(操作S、MAX 和MIN),输出答案。

输入样例

3

0 1 1

1 2 2

8

SUM 0 2

MAX 0 2

N 0 1

SUM 0 2

MIN 0 2

C 1 3

SUM 0 2

MAX 0 2

输出样例

3

2

1

-1

5

3

提示

一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。

题解

凭着对树剖的熟练度,20min打完180+行直接1A【只会打板

学了LCT发现其实树剖的题目都可以用LCT刷刷

LCT明天补上【如果我查得完错

UPDATE:已补LCT

果然树剖快挺多

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 20005,maxm = 100005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
char opt[10];
int h[maxn],ne = 0,N,M;
struct EDGE{int to,nxt,w,i;}ed[maxm];
inline void build(int u,int v,int w,int i){
ed[ne] = (EDGE){v,h[u],w,i}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w,i}; h[v] = ne++;
}
int fa[maxn],dep[maxn],son[maxn],V[maxn],id[maxn],P[maxn],H[maxn],top[maxn],siz[maxn];
int cnt = 0;
void dfs1(int u){
siz[u] = 1; int to;
Redge(u) if ((to = ed[k].to) != fa[u]){
dep[to] = dep[u] + 1; fa[to] = u; P[ed[k].i] = to; V[to] = ed[k].w;
dfs1(to);
siz[u] += siz[to];
if (!son[u] || siz[to] > siz[son[u]]) son[u] = to;
}
}
void dfs2(int u,int flag){
id[u] = ++cnt; H[cnt] = u; top[u] = flag ? top[fa[u]] : u; int to;
if (son[u]) dfs2(son[u],true);
Redge(u) if ((to = ed[k].to) != fa[u] && to != son[u]) dfs2(to,false);
}
int sum[4 * maxn],mx[4 * maxn],mn[4 * maxn],tag[4 * maxn],L,R;
void pup(int u){
sum[u] = sum[ls] + sum[rs];
mx[u] = max(mx[ls],mx[rs]);
mn[u] = min(mn[ls],mn[rs]);
}
void pd(int u){
if (tag[u]){
sum[ls] = -sum[ls]; sum[rs] = -sum[rs];
swap(mx[ls],mn[ls]); mx[ls] = -mx[ls]; mn[ls] = -mn[ls];
swap(mx[rs],mn[rs]); mx[rs] = -mx[rs]; mn[rs] = -mn[rs];
tag[ls] ^= 1; tag[rs] ^= 1; tag[u] ^=1;
}
}
void build(int u,int l,int r){
if (l == r){
sum[u] = mx[u] = mn[u] = V[H[l]];
return;
}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
pup(u);
}
void modify(int u,int l,int r,int v){
if (l == r) {sum[u] = mx[u] = mn[u] = v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= L) modify(ls,l,mid,v);
else modify(rs,mid + 1,r,v);
pup(u);
}
void rever(int u,int l,int r){
if (l >= L && r <= R){
sum[u] = -sum[u];
swap(mx[u],mn[u]); mx[u] = -mx[u]; mn[u] = -mn[u];
tag[u] ^= 1;
return;
}
pd(u);
int mid = l + r >> 1;
if (mid >= L) rever(ls,l,mid);
if (mid < R) rever(rs,mid + 1,r);
pup(u);
}
int Query(int u,int l,int r){
if (l >= L && r <= R) return sum[u];
pd(u);
int mid = l + r >> 1;
if (mid >= R) return Query(ls,l,mid);
else if (mid < L) return Query(rs,mid + 1,r);
else return Query(ls,l,mid) + Query(rs,mid + 1,r);
}
int Qmin(int u,int l,int r){
if (l >= L && r <= R) return mn[u];
pd(u);
int mid = l + r >> 1;
if (mid >= R) return Qmin(ls,l,mid);
else if (mid < L) return Qmin(rs,mid + 1,r);
else return min(Qmin(ls,l,mid),Qmin(rs,mid + 1,r));
}
int Qmax(int u,int l,int r){
if (l >= L && r <= R) return mx[u];
pd(u);
int mid = l + r >> 1;
if (mid >= R) return Qmax(ls,l,mid);
else if (mid < L) return Qmax(rs,mid + 1,r);
else return max(Qmax(ls,l,mid),Qmax(rs,mid + 1,r));
}
void solve1(){
int u = P[RD()],w = RD();
L = id[u]; modify(1,1,N,w);
}
void solve2(){
int u = RD() + 1,v = RD() + 1;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u,v);
L = id[top[u]]; R = id[u];
rever(1,1,N);
u = fa[top[u]];
}
if (u == v) return;
if (dep[u] > dep[v]) swap(u,v);
L = id[u] + 1; R = id[v];
rever(1,1,N);
}
void solve3(){
int u = RD() + 1,v = RD() + 1,ans = 0;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u,v);
L = id[top[u]]; R = id[u];
ans += Query(1,1,N);
u = fa[top[u]];
}
if (u != v){
if (dep[u] > dep[v]) swap(u,v);
L = id[u] + 1; R = id[v];
ans += Query(1,1,N);
}
printf("%d\n",ans);
}
void solve4(){
int u = RD() + 1,v = RD() + 1,ans = -INF;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u,v);
L = id[top[u]]; R = id[u];
ans = max(ans,Qmax(1,1,N));
u = fa[top[u]];
}
if (u != v){
if (dep[u] > dep[v]) swap(u,v);
L = id[u] + 1; R = id[v];
ans = max(ans,Qmax(1,1,N));
}
printf("%d\n",ans);
}
void solve5(){
int u = RD() + 1,v = RD() + 1,ans = INF;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u,v);
L = id[top[u]]; R = id[u];
ans = min(ans,Qmin(1,1,N));
u = fa[top[u]];
}
if (u != v){
if (dep[u] > dep[v]) swap(u,v);
L = id[u] + 1; R = id[v];
ans = min(ans,Qmin(1,1,N));
}
printf("%d\n",ans);
}
int main(){
memset(h,-1,sizeof(h));
N = RD(); int u,v,w;
REP(i,N - 1) u = RD() + 1,v = RD() + 1,w = RD(),build(u,v,w,i);
dep[1] = 1; dfs1(1); dfs2(1,0); build(1,1,N);
M = RD();
while (M--){
scanf("%s",opt);
if (opt[0] == 'C') solve1();
else if (opt[0] == 'N') solve2();
else if (opt[0] == 'S') solve3();
else if (opt[1] == 'A') solve4();
else solve5();
}
return 0;
}

LCT:【代码短但会慢一点】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define isrt(u) (!f[u] || (ch[f[u]][0] != u && ch[f[u]][1] != u))
#define isr(u) (ch[f[u]][1] == u)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define ls (ch[u][0])
#define rs (ch[u][1])
using namespace std;
const int maxn = 40005,maxm = 100005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
int rev[maxn],Min[maxn],Max[maxn],f[maxn],ch[maxn][2],sum[maxn];
int tag[maxn],V[maxn],N,M,ed[maxn];
char opt[10];
void Rever(int u){
swap(Min[u],Max[u]); Max[u] = -Max[u]; Min[u] = -Min[u];
sum[u] = -sum[u]; V[u] = -V[u];
tag[u] ^= 1;
}
void pup(int u){
Max[u] = max(Max[ls],Max[rs]);
Min[u] = min(Min[ls],Min[rs]);
if (u > N) Max[u] = max(Max[u],V[u]);
if (u > N) Min[u] = min(Min[u],V[u]);
sum[u] = sum[ls] + sum[rs] + V[u];
}
void pd(int u){
if (rev[u]){swap(ls,rs); rev[ls] ^= 1; rev[rs] ^= 1; rev[u] ^= 1;}
if (tag[u]){
if (ls) Rever(ls);
if (rs) Rever(rs);
tag[u] = 0;
}
}
void push_down(int u){
if (!isrt(u)) push_down(f[u]);
pd(u);
}
void spin(int u){
int s = isr(u),fa = f[u];
f[u] = f[fa]; if (!isrt(fa)) ch[f[fa]][isr(fa)] = u;
ch[fa][s] = ch[u][s ^ 1]; if (ch[u][s ^ 1]) f[ch[u][s ^ 1]] = fa;
f[fa] = u; ch[u][s ^ 1] = fa;
pup(fa); pup(u);
}
void splay(int u){
for (push_down(u); !isrt(u); spin(u))
if (!isrt(f[u])) spin((isr(u) ^ isr(f[u])) ? u : f[u]);
}
void Access(int u){
for (int v = 0; u; u = f[v = u])
splay(u),ch[u][1] = v,pup(u);
}
void Make_rt(int u){
Access(u); splay(u); rev[u] ^= 1;
}
void Split(int u,int v){
Make_rt(u); Access(v); splay(v);
}
void Link(int u,int v){
Make_rt(u); f[u] = v;
}
void solve1(){
int u = ed[RD()],v = RD();
splay(u); V[u] = v; pup(u);
}
void solve2(){
int u = RD() + 1,v = RD() + 1;
Split(u,v); Rever(v);
}
void solve3(){
int u = RD() + 1,v = RD() + 1;
Split(u,v);
printf("%d\n",sum[v]);
}
void solve4(){
int u = RD() + 1,v = RD() + 1;
Split(u,v);
printf("%d\n",Max[v]);
}
void solve5(){
int u = RD() + 1,v = RD() + 1;
Split(u,v);
printf("%d\n",Min[v]);
}
int main(){
N = RD();
int u,v,w,id = N;
for (int i = 0; i <= N; i++) Max[i] = -INF,Min[i] = INF;
REP(i,N - 1){
u = RD() + 1,v = RD() + 1,w = RD();
ed[i] = ++id; V[id] = Max[id] = Min[id] = sum[id] = w;
Link(u,id); Link(v,id);
}
M = RD();
while (M--){
scanf("%s",opt);
if (opt[0] == 'C') solve1();
else if (opt[0] == 'N') solve2();
else if (opt[0] == 'S') solve3();
else if (opt[1] == 'A') solve4();
else solve5();
}
return 0;
}

BZOJ2157 旅游 【树剖 或 LCT】的更多相关文章

  1. [BZOJ2157]旅游(树链剖分/LCT)

    树剖裸题,当然LCT也可以. 树剖: #include<cstdio> #include<algorithm> #define ls (x<<1) #define ...

  2. P1505 [国家集训队]旅游[树剖]

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

  3. 【BZOJ3999】【TJOI2015】旅游 树剖

    题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...

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

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

  5. BZOJ2157: 旅游 树链剖分 线段树

    http://www.lydsy.com/JudgeOnline/problem.php?id=2157   在对树中数据进行改动的时候需要很多pushdown(具体操作见代码),不然会wa,大概原因 ...

  6. 【BZOJ2157】旅游 树链剖分+线段树

    [BZOJ2157]旅游 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本 ...

  7. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  8. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  9. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

随机推荐

  1. ElasticSearch 集群原理

    节点 一个运行中的EasticSearch 被称为一个节点,而集群是由多个用于拥有相同cluster.name配置的节点组成,它们共同承担数据和负载的压力,当有新的节点加入或移除,集群会重新平均分布所 ...

  2. spring-JDBC Template

    JDBC Template概念 为简化持久化操作,spring在JDBC API之上提供JDBC Template组件 提供统一模板: 环境配置 1.创建MySQL数据库 2.搭建maven项目,并引 ...

  3. dataTables设置下拉滚动出现表头挤在一起的解决方法

    1.引入datatable的CSS文件 <link href="http://cdn.datatables.net/1.10.15/css/jquery.dataTables.min. ...

  4. httpd虚拟主机、站点访问控制、基于用户的访问控制、持久链接等应用配置实例

    httpd配置内容 httpd2.2 配置文件: /etc/httpd/conf/httpd.conf /etc/httpd/conf.d/*.conf 服务脚本: /etc/rc.d/init.d/ ...

  5. 怎么退出jQuery的each函数

    返回 'false' 将停止循环 (就像在普通的循环中使用 'break').返回 'true' 跳至下一个循环(就像在普通的循环中使用'continue'). 以下举例如何退出 each 函数和退出 ...

  6. PHP常用的自定义函数

    PHP常用的自定义函数 目录 php常用自定义函数类下载 php 设置字符编码为utf-8 路径格式化(替换双斜线为单斜线) 转码 打印输出 api返回信息 字符串截取 方法一: 方法二: 数组 字符 ...

  7. pyhton——logging日志模块的学习

    https://www.cnblogs.com/yyds/p/6901864.html 本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模 ...

  8. linux通用GPIO驱动,写GPIO文件不立即生效问题解决

    Linux开发平台实现了通用GPIO的驱动,用户通过,SHell或者系统调用能控制GPIO的输出和读取其输入值.其属性文件均在/sys/class/gpio/目录下,该目录下有export和unexp ...

  9. C语言进阶——循环语句07

    循环语句的基本工作方式: 通过条件表达式判定是否执行循环体 条件表达式遵循if语句表达式的原则 do,while,for的区别: do语句先执行后判断,循环体至少执行一次 while语句先判断后执行, ...

  10. mysql sum 为 0 的解决方法

    使用SQL语句SUM函数的时候,默认查询没有值的情况下返回的是null,而实际可能我们要用的是返回0. 解决方法:SELECT SUM(count) FROM test_table 改成: SELEC ...