首页 > 其他分享 >P2542 [AHOI2005] 航线规划

P2542 [AHOI2005] 航线规划

时间:2024-04-06 21:44:28浏览次数:20  
标签:std pb 航线 AHOI2005 int top son P2542 id

P2542 [AHOI2005] 航线规划

trick+树剖

首先删边操作困难,考虑倒序处理

发现题目中的关键性质:无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。

这说明无论何时图都是连通的,那么我们完全可以建一棵树,再考虑加边对树的影响

首先如果是树,那么两点路径唯一,关键航线数量即为路径长度。若此时加了一条边,一定会在树上形成一个环,此时环上任意一条边再断开对图的连通性不会有任何影响,那么环上的边不可能为关键航线了

这个操作其实就是路径覆盖 \(0\),树剖维护即可。

建树的操作我是用并查集维护的。

复杂度 \(O(n\log n)\)。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

typedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 30010, M = 1e6;
int n, m, k, cnt, q;
int fa[N], vis[M], h[N], ans[M];
std::map<pii, int> mp;
std::vector<pii> E;
std::vector<std::array<int, 3>> G;
int find(int x) {
	if(x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
struct node {
	int to, nxt;
} e[N << 1];
void add(int u, int v) {
	e[++cnt].to = v, e[cnt].nxt = h[u], h[u] = cnt;
}
int num;
int sz[N], dep[N], id[N], son[N], anc[N], top[N];
void dfs1(int u, int fa) {
	sz[u] = 1;
	dep[u] = dep[fa] + 1;
	anc[u] = fa;
	for(int i = h[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == fa) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	} 
}	
void dfs2(int u, int topf) {
	top[u] = topf;
	id[u] = ++num;
	if(!son[u]) return;
	dfs2(son[u], topf);
	for(int i = h[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == anc[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}
struct seg {
	int v, lzy;
} t[N << 2];
void pushup(int u) {t[u].v = t[u << 1].v + t[u << 1 | 1].v;}
void pd(int u) {
	if(!t[u].lzy) return;
	t[u << 1].v = t[u << 1 | 1].v = 0;
	t[u << 1].lzy = t[u << 1 | 1].lzy = 1;
	t[u].lzy = 0;
}
void build(int u, int l, int r) {
	if(l == r) {
		if(l != 1) t[u].v = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
	pushup(u);
}
void update(int u, int l, int r, int L, int R) {
	if(L <= l && r <= R) {
		t[u].v = 0, t[u].lzy = 1;
		return;
	}
	int mid = (l + r) >> 1; pd(u);
	if(L <= mid) update(u << 1, l, mid, L, R);
	if(R > mid) update(u << 1 | 1, mid + 1, r, L, R);
	pushup(u);
}
int query(int u, int l, int r, int L, int R) {
	if(L <= l && r <= R) return t[u].v;
	int mid = (l + r) >> 1, ret = 0; pd(u);
	if(L <= mid) ret += query(u << 1, l, mid, L, R);
	if(R > mid) ret += query(u << 1 | 1, mid + 1, r, L, R);
	return ret;
}
int qry(int u, int v) {
	int ret = 0;
	while(top[u] != top[v]) {
		if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
		ret += query(1, 1, n, id[top[u]], id[u]);
		u = anc[top[u]];
	}
	if(dep[u] > dep[v]) std::swap(u, v);
	ret += query(1, 1, n, id[u] + 1, id[v]);
	return ret;
}
void mdf(int u, int v) {
	while(top[u] != top[v]) {
		if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
		update(1, 1, n, id[top[u]], id[u]);
		u = anc[top[u]];
	}
	if(dep[u] > dep[v]) std::swap(u, v);
	update(1, 1, n, id[u] + 1, id[v]);
}
void Solve() {
	std::cin >> n >> m;
	E.pb({0, 0}), G.pb({0, 0});
	for(int i = 1; i <= n; i++) fa[i] = i;
	for(int i = 1; i <= m; i++) {
		int u, v;
		std::cin >> u >> v;
		E.pb({u, v});
		mp[{u, v}] = i;
	}
	while(1) {
		int op;
		std::cin >> op;
		if(op == -1) break;
		int u, v;
		std::cin >> u >> v;
		if(op == 1) G.pb({++q, u, v});
		else {
			G.pb({0, u, v});
			E[mp[{u, v}]] = {0, 0};
		}
		k++;
	}
	for(auto x : E) {
		if(x.fi) G.pb({0, x.fi, x.se});
	}
	std::reverse(G.begin() + 1, G.end());
	int g = G.size();
	for(int i = 1; i <= g - k - 1; i++) {
		int x = find(G[i][1]), y = find(G[i][2]);
		if(x == y) continue;
		vis[i] = 1, fa[x] = y;
		add(G[i][1], G[i][2]), add(G[i][2], G[i][1]); 
 	}
 	dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
	for(int i = 1; i < g; i++) {
		if(vis[i]) continue;
 		if(G[i][0]) {
 			ans[G[i][0]] = qry(G[i][1], G[i][2]);
 		} else {
 			mdf(G[i][1], G[i][2]);
 		}
 	}
 	for(int i = 1; i <= q; i++) std::cout << ans[i] << "\n";
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	Solve();

	return 0;
}

标签:std,pb,航线,AHOI2005,int,top,son,P2542,id
From: https://www.cnblogs.com/FireRaku/p/18117985

相关文章

  • Cesium 根据飞机航线计算飞机的Heading(偏航角)、Pitch(俯仰角)、Roll(翻滚角)
    需求设置飞机的一些坐标位置(经纬度高度),插值得到更多的坐标位置,然后飞机按照这些坐标集合形成的航线飞行,飞机的朝向、俯仰角以及飞机转弯时的翻转角根据坐标集合计算得出,而不需要手动设置heading、pitch、roll。坐标插值不知道为什么,可能是飞行速度变化太大,我用Cesium自带的插......
  • [AHOI2005] SHUFFLE 洗牌
    这是一道逆元的模板题。看到题,首先找下规律:首先想到是否存在循环,即经过多次洗牌后回到原状态的情况,但手玩了几组以后发现有循环但没有规律,只能知道循环节长度小于等于\(n\),显然会\(TLE\);所以对于一些循环节较长的数据很容易被卡掉(比如这组:900000000011)代码转载自@Ish......
  • 道路与航线
    【题意】给定n个点的图,正权无向边,正负权有向边,保证对有向边(u,v),v无法到达u,求起点出发到达所有点的最短距离。题目很朴素,目的就是理解spfa和dijkstra各自的限制。dijkstra的限制是负边和环,spfa算是暴力。。限制是时间复杂度这题保证了负数边权的特殊,整个图可被分为数个由负边连......
  • 集训队互测2023 彩虹航线
    给定一个\(n\)个点\(m\)条边的二分图,每个点的度数都\(\leqslantk\),且每条边的本质不同的备选颜色数目都\(\geqslantk\),求一组边染色,可以证明一定有解。有一个乱搞是每次在加入一条边时按照颜色从小到大,如果当前可以加入则加入,否则如果只会影响一条边则将这条边断掉后再重......
  • HighCharts 地图画航线,以及在城市点画圈
    需求:生成一个世界地图,在城市点处画一个响应式的圈,及在城市点间画一条指示性的航线分析:生成一幅世界地图需导入相关地图js文件与获取json文件,在城市点画一个响应式的圈和一条指示性的航线,需要生成序列,并指定类型,航线类型(flowmap),响应式的圆圈用render进行画圆圈,具体请看下图解决:源......
  • ACwing342. 道路与航线
    这道题是把拓扑排序和迪杰斯特拉交叉进行。#include<iostream>#include<stdio.h>#include<algorithm>#include<cstring>#include<queue>#include<vector>usingnamespacestd;typedefpair<int,int>PII;constintN=25005,M=50......
  • 碧蓝航线ALAS怎样在repo更新前设置复刻活动到最新活动
    1.修改deploy(文件位置:AzurLaneAutoScript/config/deploy.yaml)将图中的AutoUpdate临时改为false,KeepLocalChanges改为TrueAutoUpdate意思是要不要自动更新,这里如果保持原设置每次启动ALAS还是会拉取分支的改动,此时如果改动了ALAS的一些设置又同步了更新,启动是时候进主界面就可能报......
  • 【笔记】P2542 [AHOI2005] 航线规划 答辩做法
    洛谷上是可以过掉的。NFLSOJ上加强数据,还卡常,所以90pts。首先倒着做很好想。对于最终的图,我们可以tarjan缩点然后建树,边权为\(1\),表示一条割边。然后每次连两个点的时候就把树上这一段路径赋值为\(0\)。查询就是树上路径和。这些操作都可以点赋边权然后树剖来做。所以你就得......
  • echarts飞行航线图学习
    第一次接触这个理解可能不一定正确后面如果我发现有问题会更正1.npm安装echarts npminstallecharts--saveimport*asechartsfrom'echarts'//这里我在data里定义了一个也可不定义根据使用方法灵活调整this.myChart=echarts.init(this.$refs......
  • [AHOI2005]约数研究
    没错,数学也有分类了qaq,我之前学算法的时候妹学数学,今天算是被搞怕了(但还是不听ovo)学会了两种方法,主要思想还是,对于每个i来说,他在从1-n中的贡献值是n/i,也就是1-n中约数含有它的数目是n/i(厉害吧,刚学的)另外一种方法是筛法,说实话这个你应该想到的(恼),不优化会爆的(30分......