题目:

给定一棵树, 带边权。

现在有2种操作:

1.修改第i条边的权值。

2.询问u到其他一个任意点的最大距离是多少。

解法:边分治+线段树

首先我们将所有的点修改和边修改都存在对应的边里面。

然后接下来就是边分治的过程。

对于边分治的一层来说,以这条边为界分割出来。

设这条边为 x, y, w

我们把这层图上所有的边修改, 点询问都拿出来, 按照修改时间排序一下。

在切掉这条边的基础上。

然后以x为根, dfn建立一棵线段树, 记下边修改是修改在那个子树上的。

然后以y为根, dfn建立一棵线段树, 记下边修改是修改在那个子树上的。

然后对于一个修改操作来说, 就是相当于修改这颗子树的所有点的权值。

对于一个询问操作来说, 就是询问这个点到这边根的距离 + 中间这条边 + 另一边的最大值。

注意的是, 记得维护中间这条边的修改。

为了排除虚点的影响, 我就把虚点的权值设为-inf了,但是感jio是可以不用这样搞的。

总复杂度分析:

每个点只会出现在log个子图内, 每个修改和询问也最多是出现在这log个子图内。

每幅图sort + 线段树操作1次。

所以是 n * log + q * log * log。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
struct Node{
int head[N], to[N<<], nt[N<<], ct[N<<], id[N<<];
int tot;
void init(){
memset(head, -, sizeof(head));
tot = ;
}
void add(int u, int v, int cost, int fid){
ct[tot] = cost;
to[tot] = v;
nt[tot] = head[u];
id[tot] = fid;
head[u] = tot++;
}
}e[];
int n, maxn, m, white[N], cut[N<<];
void rebuild(int o, int u){
int ff = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(o == v) continue;
if(!ff){
e[].add(u, v, e[].ct[i], e[].id[i]);
e[].add(v, u, e[].ct[i], e[].id[i]);
ff = u;
}
else {
++n;
e[].add(ff, n, , ); e[].add(n, ff, , );
e[].add(n, v, e[].ct[i], e[].id[i]); e[].add(v, n, e[].ct[i], e[].id[i]);
ff = n;
}
rebuild(u, v);
}
} int sz[N], minval, id;
void get_edge(int o, int u, int num){
sz[u] = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
get_edge(u, v, num);
sz[u] += sz[v];
int tmp = max(sz[v], num - sz[v]);
if(tmp < minval){
minval = tmp;
id = i;
}
}
}
int k = , op;
int qtot = ;
pll P[N<<];
int L[N];
vector<pll> edge[N];
vector<pll> Que[N];
LL ans[N];
int col[N];
int ecol[N];
struct GG{
LL a[N];
LL seg[N<<], lazy[N<<];
int point[N];
int edis[N];
int tot = ;
int dfn[N], out[N], fdfn[N];
void dfs(int o, int u, LL dis){
sz[u] = ;
dfn[u] = ++tot;
fdfn[tot] = u;
col[u] = op;
if(u > maxn)
a[tot] = -INF;
else
a[tot] = dis;
for(pll & t : Que[u])
P[++qtot] = t;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
ecol[e[].id[i]] = op;
point[e[].id[i]] = v;
edis[e[].id[i]] = e[].ct[i];
for(pll & t : edge[e[].id[i]]){
P[++qtot] = t;
}
dfs(u, v, dis + e[].ct[i]);
sz[u] += sz[v];
}
out[u] = tot; }
void Build(int l, int r, int rt){
lazy[rt] = ;
if(l == r){
seg[rt] = a[l];
return ;
}
int m = l+r >> ;
Build(lson); Build(rson);
seg[rt] = max(seg[rt<<], seg[rt<<|]);
}
void Tree_Build(){
Build(, tot, );
}
void PushDown(int rt){
if(lazy[rt]){
lazy[rt<<] += lazy[rt];
lazy[rt<<|] += lazy[rt];
seg[rt<<] += lazy[rt];
seg[rt<<|] += lazy[rt];
lazy[rt] = ;
}
}
void Update(int L, int R, int C, int l, int r, int rt){
if(L <= l && r <= R){
seg[rt] += C;
lazy[rt] += C;
return ;
}
int m = l+r >> ;
PushDown(rt);
if(L <= m) Update(L, R, C, lson);
if(m < R) Update(L, R, C, rson);
seg[rt] = max(seg[rt<<], seg[rt<<|]);
}
void Tree_Update(int id, int ct){
int u = point[id];
Update(dfn[u], out[u], ct-edis[id], , tot, );
edis[id] = ct;
}
LL Query(int L, int l, int r, int rt){
if(l == r) return seg[rt];
PushDown(rt);
int m = l+r >> ;
if(L <= m) return Query(L, lson);
return Query(L, rson);
}
LL Tree_Query(int x){
return Query(dfn[x], , tot, );
}
void init(){
tot = ;
}
}Seg[];
void solve(int u, int num){
// cout << u << " " << num << endl;
if(num <= ) return ;
minval = inf;
get_edge(, u, num);
int nid = id;
cut[nid>>] = ;
qtot = ;
op = ;
Seg[].init();
Seg[].dfs(, e[].to[nid], );
Seg[].Tree_Build();
op = ;
Seg[].init();
Seg[].dfs(, e[].to[nid ^ ], );
Seg[].Tree_Build();
int gid = e[].id[nid];
for(pll & t : edge[gid])
P[++qtot] = t;
sort(P+, P++qtot);
for(int i = ; i <= qtot; ++i){
if(P[i].se < ){
int u = -P[i].se;
if(u == gid)
e[].ct[nid] = L[P[i].fi];
else
Seg[ecol[u]].Tree_Update(u, L[P[i].fi]);
}
else {
int u = P[i].se;
int id = col[u];
ans[P[i].fi] = max(ans[P[i].fi], Seg[id].Tree_Query(u) + Seg[id^].seg[] + e[].ct[nid]);
}
}
solve(e[].to[nid], sz[e[].to[nid]]);
solve(e[].to[nid^], sz[e[].to[nid^]]);
}
int main(){
e[].init(), e[].init();
scanf("%d", &n);
maxn = n;
for(int i = , u, v, w; i < n; ++i){
scanf("%d%d%d", &u, &v, &w);
e[].add(u, v, w, i);
e[].add(v, u, w, i);
}
int q, u;
char s[];
scanf("%d", &q);
for(int i = ; i <= q; ++i){
ans[i] = -;
scanf("%s", s);
if(s[] == 'Q'){
scanf("%d", &u);
Que[u].pb(pll(i, u));
}
else {
scanf("%d%d", &u, &L[i]);
edge[u].pb(pll(i, -u));
}
}
rebuild(, );
// cout << n << endl;
solve(, n);
for(int i = ; i <= q; ++i){
if(~ans[i])
printf("%lld\n", ans[i]);
}
return ;
}
/*
2
1 2 1
3
Q 1
Q 1
C 1 6
*/

2019ICPC上海网络赛A 边分治+线段树的更多相关文章

  1. 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树

    题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...

  2. HDU 4747 Mex (2013杭州网络赛1010题,线段树)

    Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  3. 2017ICPC北京赛区网络赛 Minimum(数学+线段树)

    描述 You are given a list of integers a0, a1, …, a2^k-1. You need to support two types of queries: 1. ...

  4. HDU 4267 A Simple Problem with Integers(2012年长春网络赛A 多颗线段树+单点查询)

    以前似乎做过类似的不过当时完全不会.现在看到就有点思路了,开始还有洋洋得意得觉得自己有不小的进步了,结果思路错了...改了很久后测试数据过了还果断爆空间... 给你一串数字A,然后是两种操作: &qu ...

  5. HDU 6444 Neko's loop ( 2018 CCPC 网络赛 && 裴蜀定理 && 线段树 )

    题目链接 题意 : 给出一个 n 个元素的环.可以任意选择起点.选完起点后.可以行走 m 步.每次前进 k 个单位.所走到的点将产生正或负贡献.问你一开始得准备多少才能使得初始资金加上在环上获取最大利 ...

  6. 2019ICPC 上海网络赛 G题 Substring(哈希)

    题意: 给了一个母串S, 每次循环给了一个模板串,问模板串在母 串中“匹配”了多少次?“匹配”的意思就是首字母和尾字母一样, 中间字母顺序可以换. 题解: 字符串hash.我们将询问字符串的首尾特殊h ...

  7. 2019ICPC 上海网络赛 L. Digit sum(二维树状数组+区间求和)

    https://nanti.jisuanke.com/t/41422 题目大意: 给出n和b,求1到n,各数在b进制下各位数之和的总和. 直接暴力模拟,TLE.. 没想到是要打表...还是太菜了. # ...

  8. 2019 上海网络赛 F Rhyme scheme (字典树DP)

    题目:https://nanti.jisuanke.com/t/41414 题意:求长度为n的第k个bell number  ,  就是第i位的选取范围在 1-(i-1)位的最大值 +1,第一位固定为 ...

  9. 线段树+单调栈+前缀和--2019icpc南昌网络赛I

    线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...

随机推荐

  1. truncate()函数

    1 truncate()方法用于截断文件,如果指定了可选参数 size,则表示截断文件为 size 个字符,截断之后 size 后面的所有字符被删除. 参考: https://www.runoob.c ...

  2. 【ABAP系列】SAP VA01屏幕增强(user-exit)

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP VA01屏幕增强(user- ...

  3. oracle--约束(主键、非空、检查)

    问题1:学号重复了,数据还可以插入成功 使用主键约束:学号是唯一标识一条数据的,所以必须唯一且不能为空 ---(1).在确定为主键的字段后添加 primary key关键字 ---(2).在创建表的后 ...

  4. python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  5. mysql部署-主从搭建

    一.安装数据库 yum -y install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release ...

  6. [Python3 填坑] 001 格式化符号 & 格式化操作符的辅助指令

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 Python 格式化符号表 举例说明 (1) %c (2) %s 与 %d (3) %o (4) %x (5) %f (6) %e (7 ...

  7. Java:CAS(乐观锁)

    本文讲解CAS机制,主要是因为最近准备面试题,发现这个问题在面试中出现的频率非常的高,因此把自己学习过程中的一些理解记录下来,希望能对大家也有帮助. 什么是悲观锁.乐观锁?在java语言里,总有一些名 ...

  8. HDU 5094 题解(状压BFS)

    题面: Maze 题目中文大意: 这个故事发生在“星际迷航”的背景下. “星际争霸”的副队长史波克落入克林贡的诡计中,被关押在他们的母亲星球Qo’noS上. 企业的上尉詹姆斯·T·柯克(James T ...

  9. Python实现视频片头和片尾添加

    import imageio imageio.plugins.ffmpeg.download() from datetime import datetime import os from moviep ...

  10. Python之字符串和正则表达式

    使用正则表达式 Python对正则表达式的支持 例子:替换字符串中的不良内容 import re def main(): sentence = '你丫是傻叉吗? 我操你大爷的. Fuck you.' ...