zoukankan      html  css  js  c++  java
  • 【SHOI2008】堵塞的交通

    题面

    题解

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

    $ ext{LCT}$

    记下每条边的删除时间,用$ ext{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
    ", 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;
    }
    
  • 相关阅读:
    动画02
    动画01
    css过渡
    06强制类型转换
    05强制类型转换
    jetson 安装opencv4.4.0
    cpp中的内置异常
    cpp中std::string和std::wstring 相互转换
    qt creator杂记
    win10 git bash 使用vim 显示 git log
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10172072.html
Copyright © 2011-2022 走看看