考虑如果两点在一个环中,那么这两点一定可以构出双联通分量.

考虑环和环镶嵌,那么两个环中的点一定都互为双联通分量.

由此,我们想到一个算法:

将删边转为反向加边,用LCT维护图.

当我们连接两个点时,分两种两种情况.

1.不连通 : 没啥说的,直接连上

2.连通 : 那么说明要被连接的两点在一个换中,如下图:

显然,整条路径上的所有点都互为双连通.

不过,与其维护点,我们维护边,将两点间所有边都设成 1.

在查询两个点是否为双联通时看看边权和是否等于边数即可(想一想,为什么 ? )

因为两点间的边都被赋值,有两种情况:

1. 两点为环,被统一赋值,显然正确.

2. 这条链被多个段落所覆盖,段落与段落之间至少有一个公共点,符合上述第二个结论,显然正确.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <string>
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
#define inf 1000000000
#define maxn 300007
#define pr pair<int,int>
using namespace std;
set <pr> b;
struct Union{
int p[maxn];
void init(){ for(int i=0;i<maxn;++i) p[i]=i; }
int find(int x){ return p[x]==x ? x : p[x]=find(p[x]);}
int merge(int a,int b){
int x=find(a),y=find(b);
if(x==y) return 1;
p[x]=y;
return 0;
}
}tree;
int tot;
int ans[maxn];
int ch[maxn][2],f[maxn],val[maxn];
int sta[maxn],tag[maxn],sumv1[maxn],addv[maxn],sumv2[maxn];
int lson(int x){ return ch[x][0]; }
int rson(int x){ return ch[x][1]; }
int get(int x){ return ch[f[x]][1]==x; }
int isRoot(int x){ return !(ch[f[x]][0]==x||ch[f[x]][1]==x); }
void mark(int x){ if(x) swap(ch[x][0],ch[x][1]),tag[x]^=1; }
void update(int x){ sumv1[x]=sumv2[x],addv[x]=1,val[x] = 1; }
void pushdown(int x){
if(tag[x]) mark(lson(x)), mark(rson(x)), tag[x]=0;
if(addv[x]) update(lson(x)),update(rson(x)),addv[x]=0;
}
void pushup(int x){
sumv1[x]=sumv1[lson(x)]+sumv1[rson(x)] + val[x];
sumv2[x]=sumv2[lson(x)]+sumv2[rson(x)] + 1;
}
void rotate(int x) {
int old=f[x],oldf=f[old],which=get(x);
if(!isRoot(old)) ch[oldf][ch[oldf][1]==old]=x;
ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
ch[x][which^1]=old,f[old]=x,f[x]=oldf;
pushup(old),pushup(x);
}
void splay(int x){
int v=0,u=x;
sta[++v]=u;
while(!isRoot(u)) sta[++v]=f[u],u=f[u];
while(v) pushdown(sta[v--]);
u=f[u];
for(int fa;(fa=f[x])!=u;rotate(x))
if(f[fa]!=u) rotate(get(fa)==get(x)?fa:x);
} void Access(int x){ for(int y=0;x;y=x,x=f[x]) splay(x),ch[x][1]=y,pushup(x); }
void makeRoot(int x){ Access(x),splay(x),mark(x); }
void split(int x,int y){ makeRoot(x),Access(y),splay(y); }
void link(int a,int b){
if(tree.merge(a,b) == 1) { makeRoot(a),Access(b),splay(b),update(b); }
else{
makeRoot(a);
f[f[a]=++tot]=b;
}
}
struct E{ int x,y; }err[maxn];
struct OPT{ int opt,x,y; }opt[maxn];
char chf[10];
int main(){
//setIO("input");
int n,m,q;
tot=100001;
scanf("%d%d%d",&n,&m,&q),tree.init();
for(int i=1;i<tot;++i) sumv1[i]=sumv2[i]=val[i]=1;
for(int i=1;i<=m;++i) {
scanf("%d%d",&err[i].x,&err[i].y);
if(err[i].y>err[i].x) swap(err[i].x,err[i].y);
}
for(int i=1;i<=q;i++) {
scanf("%s",chf);
scanf("%d%d",&opt[i].x,&opt[i].y);
if(opt[i].y>opt[i].x) swap(opt[i].x,opt[i].y);
if(chf[0]=='Z')
{
opt[i].opt=1;
b.insert(make_pair(opt[i].x,opt[i].y));
}
else opt[i].opt=0;
}
for(int i=1;i<=m;i++)
{
if(b.find(make_pair(err[i].x,err[i].y))==b.end())
{
link(err[i].x,err[i].y);
}
}
for(int i=q;i>=1;--i) {
if(opt[i].opt==1) { link(opt[i].x,opt[i].y); }
else {
int a=opt[i].x,b=opt[i].y;
if(tree.find(a)!=tree.find(b)) {ans[i]=0;continue; }
makeRoot(a),Access(b),splay(b);
if(sumv1[b]==sumv2[b]) ans[i]=1;
else ans[i]=0;
}
}
for(int i=1;i<=q;++i)
if(opt[i].opt==0) {
if(ans[i]==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}

  

BZOJ 4229: 选择 LCT_独创方法_边双的更多相关文章

  1. 【BZOJ 4229】 4229: 选择 (线段树+树链剖分)

    4229: 选择 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 67  Solved: 41 Description 现在,我想知道自己是否还有选择. ...

  2. 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好

    HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...

  3. boost/lexical_cast.hpp的简单使用方法_行动_新浪博客

    boost/lexical_cast.hpp的简单使用方法_行动_新浪博客     boost/lexical_cast.hpp的简单使用方法    (2010-03-19 16:31:13)    ...

  4. easyui datebox 只选择月份的方法

    easyui datebox 只选择月份的方法 效果如下图: 代码如下: <html > <head> <meta charset="utf-8"&g ...

  5. Vivado_MicroBlaze_问题及解决方法_汇总(不定时更新)

    Vivado_MicroBlaze_问题及解决方法_汇总(不定时更新) 标签: Vivado 2015-07-03 14:35 4453人阅读 评论(0) 收藏 举报  分类: 硬件(14)  版权声 ...

  6. 选择排序_C语言_数组

    选择排序_C语言_数组 #include <stdio.h> void select_sort(int *); int main(int argc, const char * argv[] ...

  7. JS清除选择内容的方法

    本文实例讲述了JS清除选择内容的方法.分享给大家供大家参考.具体分析如下: 今天在做一个DIV拖动的效果,发现在拖动的时候会选中页面中的文本,于是找了一下JS清除选择的内容的相关信息. 在得到的结果中 ...

  8. 解决PNG图片在IE6中背景不透明方法_解决IE6中PNG背

    解决PNG图片在IE6中背景不透明方法_解决IE6中PNG背   目录 解决代码 解决png图片在html中 解决png作为网页背景-css 1.解决PNG图片在IE6中背景不透明的CSS与JS代码 ...

  9. SDI011 读卡器自动发送00A4选择指令 解决方法

    如标题,SDI读卡器会自动发送 004A的应用选择指令 解决方法: 是Certificate Propagation 服务 弄的, 关闭就好了

随机推荐

  1. Python数据分析5-----数据规约

    1.数据规约概念和目的 数据规约是产生更小且保留数据完整性的新数据集. 意义:降低无效错误数据的影响.更有效率.降低存储成本. 2.属性规约 (1)属性合并(降维):比如PCA (2)删除不相关属性 ...

  2. C++基础 (6) 第六天 继承 虚函数 虚继承 多态 虚函数

    继承是一种耦合度很强的关系 和父类代码很多都重复的 2 继承的概念 3 继承的概念和推演 语法: class 派生类:访问修饰符 基类 代码: … … 4 继承方式与访问控制权限 相对的说法: 爹派生 ...

  3. WEBGL学习【九】立方体贴不同的纹理

    <html> <!--开始实现一个三维街景的渲染效果--> <head> <meta http-equiv="Content-Type" ...

  4. 1、Ansible初识简要介绍及安装

    1.Ansible简介 1.1 Ansible介绍 Ansible 是一个简单的自动化运维管理工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fab ...

  5. centos7把编译安装的服务通过systemctl管理

    nginx编译安装的目录是/usr/local/nginx nginx配置文件是/usr/local/nginx/conf/nginx.conf systemctl管理的服务文件在/usr/lib/s ...

  6. Yii2.0 RESTful API 认证教程

    认证介绍 和Web应用不同,RESTful APIs 通常是无状态的, 也就意味着不应使用 sessions 或 cookies, 因此每个请求应附带某种授权凭证,因为用户授权状态可能没通过 sess ...

  7. 关联规则推荐及Apriori算法

    参考这篇文章: http://blog.csdn.net/rongyongfeikai2/article/details/40457827 这条关联规则的支持度:support = P(A并B) 这条 ...

  8. Hadoop使用Java进行文件修改删除操作

    Hadoop使用Java进行文件修改删除操作 学习了:http://blog.csdn.net/menghuannvxia/article/details/44651061 学习了:http://bl ...

  9. java 抽象类和接口的差别

     语法层面上: 1)抽象类能够提供成员方法的实现细节.而接口中仅仅能存在public abstract 方法. 2)抽象类中的成员变量能够是各种类型的.而接口中的成员变量仅仅能是public st ...

  10. 【机房重构】—上机&amp;订餐

    前几天通过UML图中的时序图.让我对于机房重构中的每一条线理解的更加清晰.曾经认为上机特别的乱,在一次偶遇中,得知了原来它能够转化成我们平时订餐.以下就听我说一说上机&订餐的故事吧! 又是发生 ...