题意:给你一张无向图,有若干次操作,每次操作会修改一条边的边权,每次修改后输出1到n的最短路。修改相互独立。

思路:我们先以起点和终点为根,找出最短路径树,现在有两种情况:

1:修改的边不是1到n的最短路上的边,那么可能出现的情况就是这条边的权值变得足够小,出现了新的最短路,那么我们只需判断一下是不是出现了新的最短路即可,假设这条边的两端是x, y,修改后的权值是z,dis1是从1开始的最短路,dis2是从n开始的最短路,那么ans = min(dis1[n], dis1[x] +dis2[y] + z, dis1[y] + dis2[x] + z)。

2:修改的边是1到n的最短路上的边,这个相对麻烦一点,因为我们需要知道原来不是最短路的路径,会不会因为这次修改而变成最短路。因为是最短路径树,所以如果不考虑修改的这条边还想到达终点,我们必须要添加一条非树边了。我们可以算出经过非树边的路径长度(同1),然后考虑它的影响范围。可以发现,影响范围是这条非树边路径和原最短路没有重合的部分,把原最短路看成一个序列的话,问题转化成了一个区间取最小值,用线段树维护即可。

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
#define LL long long
#define piii pair<pii, int>
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
using namespace std;
const int maxn = 200010;
vector<piii> G[maxn];
piii edge[maxn];
int n;
map<int, int> mp;
void add(int x, int y, int z, int id) {
G[x].push_back(make_pair(make_pair(y, z), id));
G[y].push_back(make_pair(make_pair(x, z), id));
}
struct node {
bool flag;
LL mi, Set;
};
struct SegmentTree {
int n;
node tr[maxn * 4];
void pushup(int o) {
tr[o].mi = min(tr[ls(o)].mi, tr[rs(o)].mi);
} void maintain(int o, LL val) {
tr[o].Set = min(tr[o].Set, val);
tr[o].mi = min(tr[o].mi, tr[o].Set);
tr[o].flag = 1;
} void pushdown(int o) {
if(tr[o].flag) {
maintain(ls(o), tr[o].Set);
maintain(rs(o), tr[o].Set);
tr[o].Set = 1e18;
tr[o].flag = 0;
}
} void build(int o, int l, int r) {
if(l == r) {
tr[o].mi = 1e18;
tr[o].flag = 0;
tr[o].Set = 1e18;
return;
}
int mid = (l + r) >> 1;
build(ls(o), l, mid);
build(rs(o), mid + 1, r);
tr[o].mi = 1e18;
tr[o].flag = 0;
tr[o].Set = 1e18;
} void update(int o, int l, int r, int ql, int qr, LL val) {
if(ql > qr) return;
if(l == 0) return;
if(l >= ql && r <= qr) {
maintain(o, val);
return;
}
pushdown(o);
int mid = (l + r) >> 1;
if(ql <= mid) update(ls(o), l, mid, ql, qr, val);
if(qr > mid) update(rs(o), mid + 1, r, ql, qr, val);
pushup(o);
} LL query(int o, int l, int r, int pos) {
if(l == r && l == pos) {
return tr[o].mi;
}
pushdown(o);
int mid = (l + r) >> 1;
if(pos <= mid) return query(ls(o), l, mid, pos);
else return query(rs(o), mid + 1, r, pos);
}
};
SegmentTree st;
struct Dj {
priority_queue<pair<long long, int> > q;
pii pre[maxn];
bool in_line[maxn], v[maxn], in_tree[maxn], is_line[maxn];
LL dis[maxn];
vector<int> G1[maxn];
int f[maxn];
vector<int> line;
vector<LL> re; void add1(int x, int y) {
G1[x].push_back(y);
G1[y].push_back(x);
} void dijkstra(int s) {
memset(v, 0, sizeof(v));
memset(dis, 0x3f, sizeof(dis));
q.push(make_pair(0, s));
dis[s] = 0;
while(q.size()) {
int x = q.top().second;
q.pop();
if(v[x]) continue;
v[x] = 1;
for (int i = 0; i < G[x].size(); i++) {
int y = G[x][i].first.first;
LL z = G[x][i].first.second;
if(v[y]) continue;
if(dis[y] > dis[x] + z) {
dis[y] = dis[x] + z;
pre[y] = make_pair(x, G[x][i].second);
q.push(make_pair(-dis[y], y));
}
}
}
} void dfs(int x, int flag, int fa) {
f[x] = flag;
for (int i = 0 ; i < G1[x].size(); i++) {
int y = G1[x][i];
if(y == fa || is_line[y]) continue;
dfs(y, flag, x);
}
} void solve(int s) {
for (int i = 1; i <= n; i++) {
if(i == s) continue;
add1(i, pre[i].first);
in_tree[pre[i].second] = 1;
}
for (int i = n + 1 - s; i != s; i = pre[i].first) {
line.push_back(i);
in_line[pre[i].second] = 1;
is_line[i] = 1;
}
line.push_back(s);
is_line[s] = 1;
for (int i = 0; i < line.size(); i++) {
int y = line[i];
dfs(y, y, -1);
}
}
};
Dj dj1, dj2;
int main() {
int x, y, z, m, T;
// freopen("1163F.in", "r", stdin);
// freopen("1163F.out", "w", stdout);
scanf("%d%d%d", &n, &m, &T);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
edge[i] = make_pair(make_pair(x, y), z);
add(x, y, z, i);
}
dj1.dijkstra(1), dj2.dijkstra(n);
dj1.solve(1), dj2.solve(n);
int cnt = 0;
for (int i = dj1.line.size() - 1; i >= 0; i--) {
mp[dj1.line[i]] = ++cnt;
}
st.build(1, 1, cnt - 1);
for (int i = 1; i <= m; i++) {
if(dj1.in_tree[i] && dj2.in_tree[i]) continue;
else {
int x = edge[i].first.first, y = edge[i].first.second;
LL tmp = 1e18;
int l, r;
l = min(mp[dj1.f[x]], mp[dj2.f[y]]), r = max(mp[dj1.f[x]], mp[dj2.f[y]]);
tmp = dj1.dis[x] + dj2.dis[y] + edge[i].second;
if(l >= 1 && r <= cnt)
st.update(1, 1, cnt - 1, l, r - 1, tmp);
swap(x, y);
l = min(mp[dj1.f[x]], mp[dj2.f[y]]), r = max(mp[dj1.f[x]], mp[dj2.f[y]]);
tmp = dj1.dis[x] + dj2.dis[y] + edge[i].second;
if(l >= 1 && r <= cnt)
st.update(1, 1, cnt - 1, l, r - 1, tmp);
}
}
int cnt_T = 0;
while(T--) {
cnt_T++;
LL ans = 0;
scanf("%d%d", &x, &y);
int l1 = edge[x].first.first, r1 = edge[x].first.second;
if(!dj1.in_line[x]) {
ans = dj1.dis[n];
ans = min(ans, min(dj1.dis[l1] + dj2.dis[r1] + y, dj1.dis[r1] + dj2.dis[l1] + y));
printf("%lld\n", ans);
} else {
LL ans = dj1.dis[l1] + dj2.dis[r1] + y;
ans = min(ans, dj1.dis[r1] + dj2.dis[l1] + y);
int now = min(mp[l1], mp[r1]);
printf("%lld\n", min(ans, st.query(1, 1, cnt - 1, now)));
}
}
}

  

Codeforces 1163F 最短路 + 线段树 (删边最短路)的更多相关文章

  1. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  2. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  3. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  4. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  5. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  6. CodeForces 786B Legacy(线段树优化建图+最短路)

    [题目链接] http://codeforces.com/problemset/problem/786/B [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...

  7. 【转】Codeforces Round #406 (Div. 1) B. Legacy 线段树建图&&最短路

    B. Legacy 题目连接: http://codeforces.com/contest/786/problem/B Description Rick and his co-workers have ...

  8. [TJOI2012]桥(最短路+线段树)

    有n个岛屿, m座桥,每座桥连通两座岛屿,桥上会有一些敌人,玩家只有消灭了桥上的敌人才能通过,与此同时桥上的敌人会对玩家造成一定伤害.而且会有一个大Boss镇守一座桥,以玩家目前的能力,是不可能通过的 ...

  9. Codeforces 1132G Greedy Subsequences [线段树]

    洛谷 Codeforces 看到题解那么少就来发一篇吧-- 思路 看完题目一脸懵逼,感觉无从下手. 莫名其妙地想到笛卡尔树,但笛卡尔树好像并没有太大作用. 考虑把笛卡尔树改一下:每个点的父亲设为它的右 ...

随机推荐

  1. VoIP系统大盘点

    一.VoIP拓扑 PBX是程控交换机,程控交换机有实体交换机和软件模拟的交换机. 软件模拟的交换机,即交换机服务器,常用开源的sip服务器有asterisk,freepbx, opensip, fre ...

  2. (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape 错误

    使用网页版jupyder在读取桌面文件时,刚开始我的代码是: baseball = pd.read_csv('C:\Users\TuZhiqiang\Desktop\result.csv')print ...

  3. eclipse调试代码无法查看jdk变量解决方法

    1.无法查看jdk变量原因 oracle在公司在编译jdk的时候,把debug给关闭了,现在需要我们自己重新打包编译一次 2.eclipse创建一个普通java项目,取名叫jdk 3.导入jdk源码, ...

  4. mongodb增删改查基础语法

    转载:https://blog.csdn.net/u012206617/article/details/91047239 1. use DataBaseName 切换/创建数据库use mydb 2. ...

  5. python 在图像上写中文字体 (python write Chinese in image)

    本人处理图像的时候经常使用opencv的包,但是 cv2.putText 显示不了中文,所以查找了如何在python在图像上写中文的方法,在伟大的Stack Overflow上面找到一个方法,分享给大 ...

  6. 眼前一亮的WI微逸输入法

    手机上找了好多输入法,比如百度,谷歌,手心等,百度太花哨,pass:谷歌不知为何反映慢,也pass:手心颜值低,哈哈!!偶遇WI输入法,试用了不错.故推荐之,下面为界面截图:

  7. [BOOKS]Big Data: Principles and best practices of scalable realtime data systems

  8. vs code常用插件(python)

    1.chinese 作用:vscode设置为中文. 使用方法:Ctrl+Shift+P:输入 "config":选择zh 2.python 作用:调试 3.autoDocstrin ...

  9. doT模板引擎

    doT模板引擎是一个比较高效的引擎,一直都在使用,只有3kb大小,简洁的语法,无任何依赖,简单易用:下面的代码直接拷贝引用就可以使用: 插件代码 (function(){function p(b,a, ...

  10. jdbc 可处理数据库事物的通用增删查改函数

    首先弄清四种隔离级别的和三种数据并发 之间的关系 通用查询函数 //使用PreparedStatement实现对不同表的通用的返回一个对象的查询操作 //使用泛型机制,参数里先传入一个类的类型 pub ...