2019ICPC上海网络赛A 边分治+线段树
题目:
给定一棵树, 带边权。
现在有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 边分治+线段树的更多相关文章
- 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树
题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...
- HDU 4747 Mex (2013杭州网络赛1010题,线段树)
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- 2017ICPC北京赛区网络赛 Minimum(数学+线段树)
描述 You are given a list of integers a0, a1, …, a2^k-1. You need to support two types of queries: 1. ...
- HDU 4267 A Simple Problem with Integers(2012年长春网络赛A 多颗线段树+单点查询)
以前似乎做过类似的不过当时完全不会.现在看到就有点思路了,开始还有洋洋得意得觉得自己有不小的进步了,结果思路错了...改了很久后测试数据过了还果断爆空间... 给你一串数字A,然后是两种操作: &qu ...
- HDU 6444 Neko's loop ( 2018 CCPC 网络赛 && 裴蜀定理 && 线段树 )
题目链接 题意 : 给出一个 n 个元素的环.可以任意选择起点.选完起点后.可以行走 m 步.每次前进 k 个单位.所走到的点将产生正或负贡献.问你一开始得准备多少才能使得初始资金加上在环上获取最大利 ...
- 2019ICPC 上海网络赛 G题 Substring(哈希)
题意: 给了一个母串S, 每次循环给了一个模板串,问模板串在母 串中“匹配”了多少次?“匹配”的意思就是首字母和尾字母一样, 中间字母顺序可以换. 题解: 字符串hash.我们将询问字符串的首尾特殊h ...
- 2019ICPC 上海网络赛 L. Digit sum(二维树状数组+区间求和)
https://nanti.jisuanke.com/t/41422 题目大意: 给出n和b,求1到n,各数在b进制下各位数之和的总和. 直接暴力模拟,TLE.. 没想到是要打表...还是太菜了. # ...
- 2019 上海网络赛 F Rhyme scheme (字典树DP)
题目:https://nanti.jisuanke.com/t/41414 题意:求长度为n的第k个bell number , 就是第i位的选取范围在 1-(i-1)位的最大值 +1,第一位固定为 ...
- 线段树+单调栈+前缀和--2019icpc南昌网络赛I
线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...
随机推荐
- G2 基本使用 折线图 柱状图 饼图 基本配置
G2的基本使用 1.浏览器引入 <!-- 引入在线资源 --> <script src="https://gw.alipayobjects.com/os/lib/antv ...
- 35 怎么优化join
35 怎么优化join 上一篇介绍了join的两种算法:nlj和bnl create table t1(id int primary key, a int, b int, index(a)); cre ...
- python接口自动化:调试接口的代码(无token情况下)
实现代码如下: #接口调试 import requests,time class api_demo1: def __init__(self,RequestWay,url,data): self.s=r ...
- pandas 入门(3)
from pandas import Series, DataFrame, Index import numpy as np # 层次化索引 对数据重塑和分组操作很有用 data = Series(n ...
- 洛谷 P1462 通往奥格瑞玛的道路(二分答案,堆优化dijkstra)
传送门 解题思路 首先看题目问题,求经过的所有城市中最多的一次收取的费用的最小值是多少.一看“最大值最小”就想到了二分答案. 在读一遍题目,就是二分收取的费用,然后对于每一个二分的费用,跑一边最短路, ...
- python 更快地判断数字的奇数还是偶数
使用 按位与运算符(&) 将能更加快速地判断一个整数是奇数还是偶数 使用举例如下: def check_number(n): if n & 1: return '奇数' else: r ...
- 回溯---Permutations II
47.Permutations II (Medium)](https://leetcode.com/problems/permutations-ii/description/) [1,1,2] hav ...
- [译]理解 SwiftUI 里的属性装饰器@State, @Binding, @ObservedObject, @EnvironmentObject
原文地址:https://mecid.github.io/2019/06/12/understanding-property-wrappers-in-swiftui/ @States 通过使用 @St ...
- git恢复彻底删除的分支
由于一时疏忽,错误的删除了未发布正式的开发分支,经查资料已恢复分支,特此记录 查看Git日志 git reflog |grep 'filter_or_gwf' 以下日志为已删除分支 filter_or ...
- C#/.NET VS2017+ EF+SQLite.CodeFirst——真正实现CodeFirst
本文所介绍的是真正的EF+CodeFirst,不需要提前建表,由代码自动生成! 进行前需要准备的: 1.下载Sqlite Experthttp://www.sqliteexpert.com/downl ...