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 ...
随机推荐
- android window(四)WindowToken
在WindowManagerService中有两种常见的Token,WindowToken,和AppWindowToken. WindowToken http://androidxref.com/6. ...
- 如何给vue 日期控件赋值
项目中需要用到日期时间插件,尝试用bootstrap.element的时间插件都各有各的报错,对于一个菜鸟来说真的是很痛苦啊.终于,最后用了layDate实现了需要的功能 最终效果: 使用步骤: 1. ...
- debian下重装mysql
mysql总是报错,说sock文件不存在,网上若干方法,更改权限,更改配置文件,结果还是不能正常生成.sock文件.没办法,删除,重新安装. 完全删除: 删除 mysqlsudo apt-get au ...
- Java基础/利用fastjson序列化对象为JSON
利用fastjson序列化对象为JSON 参考博客:http://blog.csdn.net/zeuskingzb/article/details/17468079 Step1:定义实体类 //用户类 ...
- 关于服务器无法在已发送http表头之后设置状态问题
Response.ClearHeaders()方法 ClearHeaders方法只删除头信息,而不删除Response显示输出信息. this.Response.BufferOutput = true ...
- Kubernetes kubeadm 安装记录
Kubernetes kubeadm 安装记录 注:比较乱,都是一些预见到的错误 kubernetes yum 源 cat /etc/yum.repos.d/kubernetes.repo [kube ...
- linux系统中的基础监控(硬盘,内存,系统负载,CPU,网络等)
Linux系统常见日常监控 系统信息 查看 CentOS 版本号:cat /etc/redhat-release 综合监控 nmon 系统负载 命令:w(判断整体瓶颈) 12:04:52 up 1 ...
- C++ 中赋值运算符重载以及深拷贝浅拷贝解析
转载自:http://blog.csdn.net/business122/article/details/21242857 关键词:构造函数,浅拷贝,深拷贝,堆栈(stack),堆heap,赋值运算符 ...
- 将查询列表内容保存到excel表格中,并保存到相应的盘中
1.先导入相应的jar包 2.一个小的Demo测试[实体类+测试类:保存excel的方法] Student实体类 public class Student{ private int id; priva ...
- JDK11 | 第二篇 : JShell 工具
文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/saHBSTo4OjsIIqv_ixigjg 一.简介 Java Shell工具是JDK1. ...