zoukankan      html  css  js  c++  java
  • 【bzoj4229】选择 离线+LCT

    题目描述

    现在,我想知道自己是否还有选择。
    给定n个点m条边的无向图以及顺序发生的q个事件。
    每个事件都属于下面两种之一:
    1、删除某一条图上仍存在的边
    2、询问是否存在两条边不相交的路径可以从点u出发到点v

    输入

    第一行三个整数n,m,q
    接下来m行,每行两个整数u,v,表示u和v之间有一条边
    接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:
    当o为’Z’时,表示删除一条u和v之间的边
    当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点v

    输出

    对于每组询问,如果存在,输出Yes,否则输出No

    样例输入

    7 8 7
    1 2
    1 3
    1 4
    2 3
    3 4
    3 7
    7 4
    5 6
    Z 1 4
    P 1 3
    P 2 4
    Z 1 3
    P 1 3
    Z 6 5
    P 5 6

    样例输出

    Yes
    Yes
    No
    No


    题解

    离线+LCT

    删边很难处理,考虑离线,时间倒流,把删边变为加边处理。

    那么问题就转化为 【bzoj4998】星球联盟

    使用LCT,加边时如果属于同一连通块,则把路径上的点缩成一个边双。并使用并查集维护边双。

    时间复杂度 $O(LCT·nlog n)$ 

    #include <set>
    #include <cstdio>
    #define N 100010
    using namespace std;
    set<pair<int , int> > s;
    int fc[N] , fv[N] , fa[N] , c[2][N] , rev[N] , px[N] , py[N] , opt[N] , qx[N] , qy[N] , ans[N];
    char str[5];
    int findc(int x)
    {
    	return x == fc[x] ? x : fc[x] = findc(fc[x]);
    }
    int findv(int x)
    {
    	return x == fv[x] ? x : fv[x] = findv(fv[x]);
    }
    inline void pushdown(int x)
    {
    	if(rev[x])
    	{
    		swap(c[0][c[0][x]] , c[1][c[0][x]]) , rev[c[0][x]] ^= 1;
    		swap(c[0][c[1][x]] , c[1][c[1][x]]) , rev[c[1][x]] ^= 1;
    		rev[x] = 0;
    	}
    }
    inline bool isroot(int x)
    {
    	return c[0][findv(fa[x])] != x && c[1][findv(fa[x])] != x;
    }
    void update(int x)
    {
    	if(!isroot(x)) update(findv(fa[x]));
    	pushdown(x);
    }
    inline void rotate(int x)
    {
    	int y = findv(fa[x]) , z = findv(fa[y]) , l = (c[1][y] == x) , r = l ^ 1;
    	if(!isroot(y)) c[c[1][z] == y][z] = x;
    	fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
    }
    inline void splay(int x)
    {
    	int y , z;
    	update(x);
    	while(!isroot(x))
    	{
    		y = findv(fa[x]) , z = findv(fa[y]);
    		if(!isroot(y))
    		{
    			if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
    			else rotate(y);
    		}
    		rotate(x);
    	}
    }
    inline void access(int x)
    {
    	int t = 0;
    	while(x) splay(x) , c[1][x] = t , t = x , x = findv(fa[x]);
    }
    inline void makeroot(int x)
    {
    	access(x) , splay(x);
    	swap(c[0][x] , c[1][x]) , rev[x] ^= 1;
    }
    void dfs(int x)
    {
    	if(!x) return;
    	if(fa[x]) fv[x] = findv(fa[x]);
    	dfs(c[0][x]) , dfs(c[1][x]);
    }
    inline void link(int x , int y)
    {
    	x = findv(x) , y = findv(y);
    	if(findc(x) != findc(y)) makeroot(x) , fa[x] = y , fc[fc[x]] = fc[y];
    	else if(x != y) makeroot(x) , access(y) , splay(y) , dfs(y);
    }
    int main()
    {
    	int n , m , q , i;
    	scanf("%d%d%d" , &n , &m , &q);
    	for(i = 1 ; i <= n ; i ++ ) fc[i] = fv[i] = i;
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &px[i] , &py[i]);
    	for(i = 1 ; i <= q ; i ++ )
    	{
    		scanf("%s%d%d" , str , &qx[i] , &qy[i]);
    		if(str[0] == 'Z') opt[i] = 1 , s.insert(make_pair(min(qx[i] , qy[i]) , max(qx[i] , qy[i])));
    	}
    	for(i = 1 ; i <= m ; i ++ )
    		if(s.find(make_pair(min(px[i] , py[i]) , max(px[i] , py[i]))) == s.end())
    			link(px[i] , py[i]);
    	for(i = q ; i ; i -- )
    	{
    		if(opt[i]) link(qx[i] , qy[i]);
    		else ans[i] = (findv(qx[i]) == findv(qy[i]));
    	}
    	for(i = 1 ; i <= q ; i ++ )
    		if(!opt[i])
    			puts(ans[i] ? "Yes" : "No");
    	return 0;
    }
    

     

  • 相关阅读:
    Hadoop技术内幕——Hadoop配置信息处理
    协程,线程池
    线程知识点(锁,信号量,队列,条件)
    进程的概念
    socketserver网络编程简单的小例子
    socket 发送文件
    网络编程
    正则表达式
    面对对象--多态封装
    创建可管理的属性:property
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7888949.html
Copyright © 2011-2022 走看看