题目描述

\(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| \leq 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\)),输出答案。

输入输出样例

输入样例#1:

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

输出样例#1:

3
2
1
-1
5
3

说明

很容易的基础题哦>.<

思路:如果说这道题是点权的话,那么就是一道树链剖分的板子题,但是,这道题是边权,那怎么办呢?可以发现,每个儿子只有一个父亲,那么我们就可以用这个儿子的点权来代替它与它父亲之间的边权,然后用树链剖分+线段树维护最大值,最小值和区间和即可。

代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 200007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int inf=0x7fffffff;
int n,m,num,head[maxn],a[maxn],size[maxn],d[maxn],top[maxn];
int cnt,sum[maxn<<2],lazy[maxn<<2],maxx[maxn<<2],minn[maxn<<2];
int fa[maxn],id[maxn],zrj[maxn],son[maxn];
char s1[8];
inline int qread() {
char c=getchar();int num=0,f=1;
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) num=num*10+c-'0';
return num*f;
}
struct node {
int v,w,nxt;
}e[maxn<<1];
inline void ct(int u, int v, int w) {
e[++num].v=v;
e[num].w=w;
e[num].nxt=head[u];
head[u]=num;
}
void dfs1(int u) {
size[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]) {
d[v]=d[u]+1;
fa[v]=u;
zrj[v]=e[i].w;
dfs1(v);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
}
void dfs2(int u, int t) {
id[u]=++cnt;
top[u]=t;
a[cnt]=zrj[u];
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
inline void pushup(int rt) {
sum[rt]=sum[ls]+sum[rs];
maxx[rt]=max(maxx[ls],maxx[rs]);
minn[rt]=min(minn[ls],minn[rs]);
}
inline void pushdown(int rt) {
if(lazy[rt]) {
sum[ls]=-sum[ls],lazy[ls]^=1;
sum[rs]=-sum[rs],lazy[rs]^=1;
int t1=maxx[ls],t2=maxx[rs],s1=minn[ls],s2=minn[rs];
maxx[ls]=-s1,maxx[rs]=-s2,minn[ls]=-t1,minn[rs]=-t2;
lazy[rt]=0;
}
}
void build(int rt, int l, int r) {
if(l==r) {
sum[rt]=maxx[rt]=minn[rt]=a[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void add(int rt, int l, int r, int L, int val) {
if(l==r) {
sum[rt]=maxx[rt]=minn[rt]=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid) add(ls,l,mid,L,val);
else add(rs,mid+1,r,L,val);
pushup(rt);
}
void modify(int rt, int l, int r, int L, int R) {
if(L>r||R<l) return;
if(L<=l&&r<=R) {
sum[rt]=-sum[rt],lazy[rt]^=1;
int t=maxx[rt],s=minn[rt];
maxx[rt]=-s,minn[rt]=-t;
return;
}
int mid=(l+r)>>1;
pushdown(rt);
modify(ls,l,mid,L,R),modify(rs,mid+1,r,L,R);
pushup(rt);
}
int csum(int rt, int l, int r, int L, int R) {
if(L>r||R<l) return 0;
if(L<=l&&r<=R) return sum[rt];
int mid=(l+r)>>1;
pushdown(rt);
return csum(ls,l,mid,L,R)+csum(rs,mid+1,r,L,R);
}
int cmax(int rt, int l, int r, int L, int R) {
if(L>r||R<l) return -inf;
if(L<=l&&r<=R) return maxx[rt];
int mid=(l+r)>>1,ans=-inf;
pushdown(rt);
if(L<=mid) ans=max(ans,cmax(ls,l,mid,L,R));
if(R>mid) ans=max(ans,cmax(rs,mid+1,r,L,R));
return ans;
}
int cmin(int rt, int l, int r, int L, int R) {
if(L>r||R<l) return inf;
if(L<=l&&r<=R) return minn[rt];
int mid=(l+r)>>1,ans=inf;
pushdown(rt);
if(L<=mid) ans=min(ans,cmin(ls,l,mid,L,R));
if(R>mid) ans=min(ans,cmin(rs,mid+1,r,L,R));
return ans;
}
void cal(int x, int y) {
int fx=top[x],fy=top[y];
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
modify(1,1,cnt,id[fx],id[x]);
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
modify(1,1,cnt,id[x]+1,id[y]);
}
int query_max(int x, int y) {
int fx=top[x],fy=top[y],ans=-inf;
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
ans=max(ans,cmax(1,1,cnt,id[fx],id[x]));
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
ans=max(ans,cmax(1,1,cnt,id[x]+1,id[y]));
return ans;
}
int query_min(int x, int y) {
int fx=top[x],fy=top[y],ans=inf;
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
ans=min(ans,cmin(1,1,cnt,id[fx],id[x]));
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
ans=min(ans,cmin(1,1,cnt,id[x]+1,id[y]));
return ans;
}
int query_sum(int x, int y) {
int fx=top[x],fy=top[y],ans=0;
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
ans+=csum(1,1,cnt,id[fx],id[x]);
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
ans+=csum(1,1,cnt,id[x]+1,id[y]);
return ans;
}
int main() {
n=qread();
for(int i=1,u,v,w;i<n;++i) {
u=qread()+1,v=qread()+1,w=qread();
ct(u,v,w);ct(v,u,w);
}
dfs1(1);dfs2(1,1);build(1,1,n);
m=qread();
for(int i=1,x,y;i<=m;++i) {
scanf("%s",s1);x=qread()+1,y=qread()+1;
if(s1[0]=='C') add(1,1,n,id[x],y-1);
if(s1[0]=='N') cal(x,y);
if(s1[0]=='S') printf("%d\n",query_sum(x,y));
if(s1[1]=='I') printf("%d\n",query_min(x,y));
if(s1[1]=='A') printf("%d\n",query_max(x,y));
}
return 0;
}

洛谷P1505 [国家集训队]旅游的更多相关文章

  1. 洛谷 P1505 [国家集训队]旅游 解题报告

    P1505 [国家集训队]旅游 题目描述 \(\tt{Ray}\) 乐忠于旅游,这次他来到了\(T\)城.\(T\)城是一个水上城市,一共有 \(N\) 个景点,有些景点之间会用一座桥连接.为了方便游 ...

  2. 洛谷 P1505 [国家集训队]旅游 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 AC代码 总结 题面 题目链接 P1505 [国家集训队]旅游 题目描述 Ray 乐 ...

  3. 2018.06.29 洛谷P1505 [国家集训队]旅游(树链剖分)

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

  4. 洛谷P1505 [国家集训队]旅游(树剖+线段树)

    传送门 这该死的码农题…… 把每一条边变为它连接的两个点中深度较浅的那一个,然后就是一堆单点修改/路径查询,不讲了 这里就讲一下怎么搞路径取反,只要打一个标记就好了,然后把区间和取反,最大最小值交换然 ...

  5. [洛谷]P1505 [国家集训队]旅游

    题目链接: 传送门 题目分析: 树剖板,支持单点修改,区间取反,区间求最大值/最小值/和 区间取反取两次等于没取,维护一个\(rev\ tag\),每次打标记用\(xor\)打,记录是否需要翻转,\( ...

  6. 模板—点分治A(容斥)(洛谷P2634 [国家集训队]聪聪可可)

    洛谷P2634 [国家集训队]聪聪可可 静态点分治 一开始还以为要把分治树建出来……• 树的结构不发生改变,点权边权都不变,那么我们利用刚刚的思路,有两种具体的分治方法.• A:朴素做法,直接找重心, ...

  7. [洛谷P1527] [国家集训队]矩阵乘法

    洛谷题目链接:[国家集训队]矩阵乘法 题目背景 原 <补丁VS错误>请前往P2761 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入 ...

  8. 洛谷P1501 [国家集训队]Tree II(LCT,Splay)

    洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...

  9. 洛谷P2619 [国家集训队2]Tree I(带权二分,Kruscal,归并排序)

    洛谷题目传送门 给一个比较有逼格的名词--WQS二分/带权二分/DP凸优化(当然这题不是DP). 用来解决一种特定类型的问题: 有\(n\)个物品,选择每一个都会有相应的权值,需要求出强制选\(nee ...

随机推荐

  1. [JSOI 2015] 最大公约数

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4488 [算法] 不妨首先枚举左端点 注意到对于任意一个正整数n , 其质因子个数是l ...

  2. poj 3469 Dual Core CPU——最小割

    题目:http://poj.org/problem?id=3469 最小割裸题. 那个限制就是在 i.j 之间连双向边. 根据本题能引出网络流中二元关系的种种. 别忘了写 if ( x==n+1 ) ...

  3. bzoj 2850 巧克力王国 —— K-D树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2850 只要暴力判断是否全选一个子树或全不选,如果都不是就进入查询: 要注意值有负,所以不是直 ...

  4. Sublime Text 全程指南(转载)

    摘要(Abstract) 本文系统全面的介绍了Sublime Text,旨在成为最优秀的Sublime Text中文教程. 更新记录 2014/09/27:完成初稿 2014/09/28: 更正打开控 ...

  5. C#如何对DataTable中的数据进行条件搜索

    经常遇到将数据库中的数据读取到DataTable中的时候再次对DataTable进行条件筛选,下面的筛选的一个例子: DataRow[] dr = dt.Select("token = '& ...

  6. Poj 2299 Ultra-QuickSort(归并排序求逆序数)

    一.题意 给定数组,求交换几次相邻元素能是数组有序. 二.题解 刚开始以为是水题,心想这不就是简单的冒泡排序么.但是毫无疑问地超时了,因为题目中n<500000,而冒泡排序总的平均时间复杂度为, ...

  7. Poj 3903 Stock Exchange(LIS)

    一.Description The world financial crisis is quite a subject. Some people are more relaxed while othe ...

  8. C语言中clock函数的使用

    #include<cstdio> #include<cstdlib> #include<ctime> using namespace std; int main() ...

  9. 阻止文件不被上传到iCloud

    转自:http://blog.csdn.net/a921800467b/article/details/38386787 http://www.cocoachina.com/bbs/read.php? ...

  10. Python-通过socket实现一个小型的端口检测工具

    实验机器IP:192.168.220.139,端口开放情况 代码 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import ...