洛谷P1505 [国家集训队]旅游
题目描述
R
a
y
Ray
Ray 乐忠于旅游,这次他来到了
T
T
T 城。
T
T
T 城是一个水上城市,一共有
N
N
N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,$T $城的任意两个景点之间有且只有一条路径。换句话说,
T
T
T 城中只有
N
−
1
N − 1
N−1 座桥。
R a y Ray Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度 w w w,也就是说, R a y Ray Ray 经过这座桥会增加 w w w 的愉悦度,这或许是正的也可能是负的。有时, R a y Ray Ray 看待同一座桥的心情也会发生改变。
现在, R a y Ray Ray 想让你帮他计算从 u u u 景点到 v v v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。
输入输出格式
输入格式:
输入的第一行包含一个整数
N
N
N,表示
T
T
T 城中的景点个数。景点编号为
0...
N
−
1
0...N − 1
0...N−1。
接下来 N − 1 N − 1 N−1 行,每行三个整数 u 、 v u、v u、v 和 w w w,表示有一条 u u u 到 v v v,使 R a y Ray Ray 愉悦度增加 w w w 的桥。桥的编号为 1... N − 1 1...N − 1 1...N−1。 ∣ w ∣ < = 1000 |w| <= 1000 ∣w∣<=1000。 输入的第 N + 1 N + 1 N+1 行包含一个整数 M M M,表示 R a y Ray Ray 的操作数目。
接下来有 M M M 行,每行描述了一个操作,操作有如下五种形式:
C i w C i w Ciw,表示 R a y Ray Ray 对于经过第i 座桥的愉悦度变成了 w w w。
N u v N u v Nuv,表示 R a y Ray Ray 对于经过景点 u u u 到 v v v 的路径上的每一座桥的愉悦度都变成原来的相反数。
S U M u v SUM u v SUMuv,表示询问从景点 u u u 到 v v v 所获得的总愉悦度。
M A X u v MAX u v MAXuv,表示询问从景点 u u u 到 v v v 的路径上的所有桥中某一座桥所提供的最大愉悦度。
M I N u v MIN u v MINuv,表示询问从景点 u u u 到 v v v 的路径上的所有桥中某一座桥所提供的最小愉悦度。
测试数据保证,任意时刻, R a y Ray Ray 对于经过每一座桥的愉悦度的绝对值小于等于 1000 1000 1000。
输出格式:
对于每一个询问(操作
S
、
M
A
X
S、MAX
S、MAX 和
M
I
N
MIN
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
emmm
这道题是一道很经典的树剖模板题,他基本上维护了日常线段树维护的所有东西。什么区间最大值,最小值,单点修改,区间乘法 。光线段树部分就码了100多行。
一般的树链剖分维护的都是点权,但这个题是维护的边权,怎么办呢。仔细观察 我们可以发现每一个节点有且只有一个父亲 (废话) ,那么说,每个节点连向父亲的边都是唯一的。所以我们可以把边权转移到这条边深度更深的点上。这样除了根节点每一个节点都拥有了一个点权。我们在修改一条路径的时候只需要正常修改这条路径上除了lca的所有点就可以了
比如这样
ans += querys(1, num[x] + 1, num[y]);
在 x 和 y 的top相同时 , 设x为深度较小的那个点,则x就为lca。因为我们不改lca,所以我们就修改num[ x ] + 1 到 num[ y ]。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 120000;
#define ll long long
#define ls now<<1
#define rs now<<1|1
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
return x * f;
}
struct node
{
ll f, t, v;
}e[maxn << 1];
struct tree
{
ll l, r, sum, maxx, minn, add, mul , num;
}tre[maxn << 2];
ll n, m, tot, cnt;
ll head[maxn], nxt[maxn << 1], used[maxn], dep[maxn], fa[maxn], sz[maxn], w1[maxn];
ll w2[maxn] , son[maxn] , top[maxn] , num[maxn];
inline void buildnode(ll a, ll b , ll c)
{
tot++;
e[tot].f = a;
e[tot].t = b;
e[tot].v = c;
nxt[tot] = head[a];
head[a] = tot;
}
inline void pushup(ll now)
{
tre[now].sum = tre[ls].sum + tre[rs].sum;
tre[now].maxx = max(tre[ls].maxx, tre[rs].maxx);
tre[now].minn = min(tre[ls].minn, tre[rs].minn);
}
inline void build(ll now, ll l, ll r)
{
tre[now].l = l;
tre[now].r = r;
tre[now].num = r - l + 1;
if (l == r)
{
tre[now].sum = w2[l];
tre[now].maxx = w2[l];
tre[now].minn = w2[l];
return;
}
ll mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1 , r);
pushup(now);
}
inline void pushdown(ll now)
{
if (tre[now].mul)
{
tre[ls].sum *= -1;
tre[rs].sum *= -1;
ll t = tre[ls].maxx;
tre[ls].maxx = -tre[ls].minn;
tre[ls].minn = -t;
t = tre[rs].maxx;
tre[rs].maxx = -tre[rs].minn;
tre[rs].minn = -t;
}
tre[ls].mul = (tre[ls].mul + tre[now].mul) % 2;
tre[rs].mul = (tre[rs].mul + tre[now].mul) % 2;
tre[now].mul = 0;
}
inline void update1(ll now, ll x , ll p)
{
if (tre[now].l == tre[now].r)
{
tre[now].sum = p;
tre[now].maxx = p;
tre[now].minn = p;
return;
}
pushdown(now);
ll mid = (tre[now].l + tre[now].r) >> 1;
if (x <= mid) update1(ls, x, p);
if (x > mid) update1(rs, x, p);
pushup(now);
}
inline void update2(ll now, ll l, ll r)
{
if (l <= tre[now].l && tre[now].r <= r)
{
tre[now].sum = -tre[now].sum;
tre[now].mul = (tre[now].mul + 1) % 2;
ll t = tre[now].maxx;
tre[now].maxx = -tre[now].minn;
tre[now].minn = -t;
return;
}
pushdown(now);
ll mid = (tre[now].l + tre[now].r) >> 1;
if (l <= mid) update2(ls, l, r);
if (r > mid) update2(rs, l, r);
pushup(now);
}
inline void dfs1(ll x, ll fat)
{
dep[x] = dep[fat] + 1;
fa[x] = fat;
sz[x] = 1;
int k = -1;
for (int i = head[x]; i; i = nxt[i])
{
int u = e[i].t;
if (u == fa[x]) continue;
w1[u] = e[i].v;
dfs1(u, x);
sz[x] += sz[u];
if (sz[u] > k) k = sz[u], son[x] = u;
}
}
inline void dfs2(ll x , ll topx)
{
num[x] = ++cnt;
w2[cnt] = w1[x];
top[x] = topx;
if (!son[x]) return;
dfs2(son[x], topx);
for (int i = head[x]; i; i = nxt[i])
{
int u = e[i].t;
if (u == fa[x] || u == son[x]) continue;
dfs2(u, u);
}
}
inline int querys(ll now, ll l, ll r)
{
if (l <= tre[now].l && tre[now].r <= r)
return tre[now].sum;
pushdown(now);
ll mid = (tre[now].l + tre[now].r) >> 1, ans = 0;
if (l <= mid) ans += querys(ls, l, r);
if (r > mid) ans += querys(rs, l, r);
return ans;
}
inline ll query_max(ll now, ll l , ll r)
{
if (l <= tre[now].l &&tre[now].r <= r)
return tre[now].maxx;
pushdown(now);
ll mid = (tre[now].l + tre[now].r) >> 1, ans = -1e9;
if (l <= mid) ans = max(ans, query_max(ls, l, r));
if (r > mid) ans = max(ans, query_max(rs, l, r));
return ans;
}
inline ll query_min(ll now, ll l , ll r)
{
if (l <= tre[now].l &&tre[now].r <= r)
return tre[now].minn;
pushdown(now);
ll mid = (tre[now].l + tre[now].r) >> 1, ans = 1e9;
if (l <= mid) ans = min(ans, query_min(ls, l, r));
if (r > mid) ans = min(ans, query_min(rs, l, r));
return ans;
}
inline ll qline(ll x, ll y)
{
ll ans = 0;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]]) swap(x , y);
ans += querys(1, num[top[x]], num[x]);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
ans += querys(1, num[x] + 1, num[y]);
return ans;
}
inline void cline(ll x, ll y)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]]) swap(x , y);
update2(1, num[top[x]], num[x]);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
update2(1, num[x] + 1, num[y]);
}
inline ll qpmax(ll x, ll y)
{
ll ans = -1e9;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]]) swap(x , y);
ans = max(ans, query_max(1, num[top[x]], num[x]));
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
ans = max(ans, query_max(1, num[x] + 1, num[y]));
return ans;
}
inline ll qpmin(ll x, ll y)
{
ll ans = 1e9;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]]) swap(x , y);
ans = min(ans, query_min(1, num[top[x]], num[x]));
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
ans = min(ans, query_min(1, num[x] + 1, num[y]));
return ans;
}
string s1 = "C", s2 = "N", s3 = "SUM", s4 = "MAX", s5 = "MIN";
int main()
{
//freopen("1.in","r",stdin);
n = read();
for (int i = 1; i <= n - 1; i++)
{
int a, b, c;
a = read(); b = read(); c = read();
buildnode(a + 1, b + 1, c);
buildnode(b + 1, a + 1, c);
}
dfs1(1 , 0);
dfs2(1 , 1);
build(1 , 1 , n);
m = read();
while (m--)
{
string s;
int a, b, k;
cin >> s >> a >> b;
a += 1 , b += 1;
if (s == s1)
{
a -= 1 , b -= 1;
if (dep[e[a * 2 - 1].f] > dep[e[a * 2 - 1].t])
k = e[a * 2 - 1].f;
else k = e[a * 2 - 1].t;
update1(1, num[k], b);
}
if (s == s2) cline(a, b);
if (s == s3) printf("%lld\n", qline(a, b));
if (s == s4) printf("%lld\n", qpmax(a, b));
if (s == s5) printf("%lld\n", qpmin(a, b));
}
return 0;
}
总的来说这个题代码量还是大。所以说做这个题的时候一定要仔细。。
End;