【SHOI2008】堵塞的交通

题面

题解

这里提供几种不用脑子的算法(当然是离线的)

$\text{LCT}$

记下每条边的删除时间,用$\text{LCT}$维护最大生成树,每次加进一条边时,跟原来那条链上的做比较,删除那条删除时间最短的边即可。

线段树分治

这个算法将每条边的加入和删除时间加入到线段树中,所以在遍历到叶子节点时,那个时刻存在的边都已经在并查集上了,于是直接判断即可。

并查集用按秩合并就可以了,撤销时记得按栈序撤销。

代码

LCT

找$hyj$去

线段树分治

我的写法可能(比较好看)并没有建线段树......

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#include<map>
#define RG register
#define clear(x, y) memset(x, y, sizeof(x))

inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while(ch != '-' && (!isdigit(ch))) ch = getchar();
	if(ch == '-') w = -1, ch = getchar();
	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int maxn(200010);
struct edge { int from, to, beg, end; };
std::pair<int, int> q[maxn], stk[maxn << 2];
std::vector<edge> e;
std::map<int, int> G[maxn];
int fa[maxn], top, q_num, n, id[2][maxn], cnt, size[maxn];
char s[10];

inline int find(int x) { while(x ^ fa[x]) x = fa[x]; return x; }
inline void merge(int x, int y)
{
	int fx = find(x), fy = find(y);
	if(fx == fy) return;
	if(size[fx] > size[fy]) std::swap(fx, fy);
	fa[fx] = fy; size[fy] += size[fx]; stk[++top] = std::make_pair(fx, fy);
}

inline void undo()
{
	int x = stk[top].first, y = stk[top--].second;
	fa[x] = x; size[y] -= size[x];
}

inline void Div(int l, int r, std::vector<edge> E)
{
	std::vector<edge> L, R;
	std::vector<edge>::iterator it;
	int mid = (l + r) >> 1, tmp = top;
	for(it = E.begin(); it != E.end(); ++it)
		if(it -> beg <= l && r <= it -> end) merge(it -> from, it -> to);
		else
		{
			if(it -> beg <= mid) L.push_back(*it);
			if(it -> end > mid)  R.push_back(*it);
		}
	if(l == r) printf("%c\n", find(q[l].first) == find(q[l].second) ? 'Y' : 'N');
	else Div(l, mid, L), Div(mid + 1, r, R);
	while(top > tmp) undo();
}

int main()
{
	n = read();
	for(RG int i = 1; i <= n; i++)
		id[0][i] = ++cnt, id[1][i] = ++cnt;
	for(RG int r1, c1, r2, c2;;)
	{
		scanf("%s", s);
		if(s[0] == 'E') break;
		r1 = read() - 1, c1 = read(), r2 = read() - 1, c2 = read();
		if(s[0] == 'O')
		{
			e.push_back((edge){id[r1][c1], id[r2][c2], q_num + 1, -1});
			G[id[r1][c1]][id[r2][c2]] = G[id[r2][c2]][id[r1][c1]] = e.size() - 1;
		}
		else if(s[0] == 'C') e[G[id[r1][c1]][id[r2][c2]]].end = q_num;
		else if(s[0] == 'A') q[++q_num] = std::make_pair(id[r1][c1], id[r2][c2]);
	}
	for(std::vector<edge>::iterator it = e.begin(); it != e.end(); ++it)
		if(it -> end == -1) it -> end = q_num;
	for(RG int i = 1; i <= n + n; i++) fa[i] = i, size[i] = 1;
	Div(1, q_num, e);
	return 0;
}
posted @ 2018-12-25 09:09  xgzc  阅读(257)  评论(0编辑  收藏  举报