题目描述

  有一个\(n\times m\)的网格,线框的交点可以扭动,边不可伸缩。网格中有一些格子里面放了'x'形的支架,这些格子不会变形,但可以整体转动。如果所有格子都不能变形,那么称这个网格稳固。

  有\(q\)个操作,每次改变一个格子的状态,即有支架给为无支架,无支架改为有支架。

  请你判断初始及每次操作后这个网格是否稳固。

  比如说下面这个网格就不稳固。

  \(n,m\leq 3000,q\leq 100000\)

题解

  先看看怎么判断一个网格是否稳固。

  先给整个网格的左边和上边加上一行一列,然后把第一行的最左边两个格子设为有支架的格子,其他的设为没支架的格子。

  样例那个图就会变成这样

  可以发现这样操作是不会改变整个图形的稳定性的。

  设格子\((i,j)\)右下角的角度为\(a_{i,j}+90\)。

  因为一个交点四个角的度数和为\(360\),所以可以列出以下方程:

\[\begin{align}
90+a_{i-1,j-1}+180-90-a_{i-1,j}+180-90-a_{i,j-1}+90+a_{i,j}&=360\\
a_{i-1,j-1}+a_{i,j}-a_{i,j-1}-a_{i-1,j}&=0
\end{align}
\]

  然后通过一些简单变换可以得到

\[a_{0,0}+a_{i,j}-a_{0,j}-a_{i,0}=0
\]

  因为\(a_{0,0}=0\),所以方程简化为

\[a_{i,j}=a_{i,0}+a_{0,j}
\]

  当\((i,j)\)有支架时\(a_{i,0}+a_{0,j}=a_{i,j}=0\),即\(a_{i,0}=-a_{0,j}\),那么我们就在图\(G\)的\(i\)和\(j+n\)两个点之间连一条边。

  显然这个图是二分图。

  因为边界上只有\(a_{0,1}=0\),所以一个点只有和\(n+1\)号点\((0,1)\)属于同一个联通块,这个点对应的角的角度才是确定的。

  当\((i,j)\)无支架时\(a_{i.j}=a_{i,0}+a_{0,j}\)。如果\(a_{i,0}\)和\(a_{0,j}\)之间有一个没有确定,那么\(a_{i,j}\)也没有确定。

  所以说,这个网格是稳定的\(\Longleftrightarrow\)图\(G\)只有一个联通块。

  现在问题就变成了:有一个\(n+m\)个点的图,有\(nm\)条边,还有\(q\)个加边删边的操作。问操作前和每一次操作完后联通块个数是不是\(1\)。

  用分治+并查集和LCT都可以做。

  可以把一定存在的边先用路径压缩的并查集处理完。

  分治+并查集:\(O(nm\alpha+q\log^2(n+m))\)

  LCT:\(O(nm\alpha+q\log (n+m))\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
vector<pii> a[400010];
int f[10010];
int r[10010];
int ans[100010];
int s1[10010];//x
int s2[10010];//f[x]
int s3[10010];//r[f[x]]
int top;
int n,m,q;
char s[10010];
int c[3010][3010];
int find(int x)
{
return f[x]==x?x:find(f[x]);
}
int find2(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int num=0;
int merge(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
return 0;
if(r[x]>r[y])
swap(x,y);
top++;
s1[top]=x;
s2[top]=y;
s3[top]=r[y];
if(r[x]==r[y])
r[y]++;
f[x]=y;
return 1;
}
int merge2(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
return 0;
if(r[x]>r[y])
swap(x,y);
f[x]=y;
if(r[x]==r[y])
r[y]++;
return 1;
}
void back()
{
f[s1[top]]=s1[top];
r[s2[top]]=s3[top];
top--;
}
void add(int p,int l,int r,int x,int y,int L,int R)
{
if(l<=L&&r>=R)
{
a[p].push_back(pii(x,y));
return;
}
int mid=(L+R)>>1;
if(l<=mid)
add(p<<1,l,r,x,y,L,mid);
if(r>mid)
add((p<<1)|1,l,r,x,y,mid+1,R);
}
void solve(int l,int r,int p)
{
int now=top;
for(auto v:a[p])
if(merge(v.first,v.second))
num++;
if(l==r)
ans[l]=(num==n+m-1);
else
{
int mid=(l+r)>>1;
solve(l,mid,p<<1);
solve(mid+1,r,(p<<1)|1);
}
while(top>now)
{
back();
num--;
}
}
int main()
{
open("grid");
scanf("%d%d%d",&n,&m,&q);
memset(c,-1,sizeof c);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='x')
c[i][j]=0;
}
for(int i=1;i<=n+m;i++)
{
f[i]=i;
r[i]=1;
}
int x,y;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
if(~c[x][y])
{
add(1,c[x][y],i-1,x,y+n,0,q);
c[x][y]=-1;
}
else
c[x][y]=i;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(~c[i][j])
{
if(c[i][j])
add(1,c[i][j],q,i,j+n,0,q);
else
if(merge2(i,j+n))
num++;
}
for(int i=1;i<=n+m;i++)
find2(i);
solve(0,q,1);
for(int i=0;i<=q;i++)
if(ans[i])
printf("S\n");
else
printf("U\n");
return 0;
}

【XSY2741】网格 分治 LCT 并查集的更多相关文章

  1. 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)

    [CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...

  2. 【BZOJ4025】二分图(线段树分治,并查集)

    [BZOJ4025]二分图(线段树分治,并查集) 题面 BZOJ 题解 是一个二分图,等价于不存在奇环. 那么直接线段树分治,用并查集维护到达根节点的距离,只计算就好了. #include<io ...

  3. 【bzoj4998】星球联盟 LCT+并查集

    题目描述 在遥远的S星系中一共有N个星球,编号为1…N.其中的一些星球决定组成联盟,以方便相互间的交流.但是,组成联盟的首要条件就是交通条件.初始时,在这N个星球间有M条太空隧道.每条太空隧道连接两个 ...

  4. 【bzoj2959】长跑 LCT+并查集

    题目描述 某校开展了同学们喜闻乐见的阳光长跑活动.为了能“为祖国健康工作五十年”,同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动.一时间操场上熙熙攘攘,摩肩接踵,盛况空前.为了 ...

  5. Dash Speed【好题,分治,并查集按秩合并】

    Dash Speed Online Judge:NOIP2016十联测,Claris#2 T3 Label:好题,分治,并查集按秩合并,LCA 题目描述 比特山是比特镇的飙车圣地.在比特山上一共有 n ...

  6. 【BZOJ2049】 [Sdoi2008]Cave 洞穴勘测 LCT/并查集

    两种方法: 1.LCT 第一次LCT,只有link-cut和询问,无限T,到COGS上找了数据,发现splay里的父亲特判出错了(MD纸张),A了,好奇的删了反转T了.... #include < ...

  7. 【BZOJ】2049: [Sdoi2008]Cave 洞穴勘测(lct/并查集)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2049 bzoj挂了..在wikioi提交,,1A-写lct的速度越来越快了-都不用debug-- 新 ...

  8. BZOJ_2049_[Sdoi_2008]_Cave_洞穴勘测_(LCT/并查集)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2049 给出一个森林,起始互不相连,现在有link和cut两种操作,问x,y是否在一棵树里. 分 ...

  9. 【BZOJ2959】长跑 (LCT+并查集)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 某校开展了同学们喜闻乐见的阳光长跑活动.为了能“为祖国健康工作五十年”,同学们纷纷离开寝室 ...

随机推荐

  1. navicat 和 pymysql

    ---------------------------------------------------相信时间的力量,单每月经过努力的时间,一切的安排都是懊脑的安排. # # ------------ ...

  2. Python入门-文件操作

    文件读取f = open('D:/工作日常/学生空姐模特护士联系方式.txt', 'r', encoding=‘utf-8’)f.read()f.close()解释file='D:/工作日常/学生空姐 ...

  3. JS 原型与原型链

    图解: 一.普通对象 跟 函数对象 JavaScript 中,一切皆对象.但对象也有区别,分为 普通对象 跟 函数对象,Object 和 Function 是 JavaScript 自带的函数对象. ...

  4. StanfordPOSTagger的用法

    或者: 然后, 由说明文档可知,nltk.tag.stanford module是与斯坦福标识符交互的模块.要到https://nlp.stanford.edu/software下载Tagger mo ...

  5. 使用Charles对iPhone进行Http(s)请求拦截(抓包)

    首先准备工具 1> Charles (下载对应操作系统的安装包进行安装,本文使用 macOS 进行演示) 2> iPhone (本文使用SE,系统版本:iOS 10) 开始 首先,对Cha ...

  6. Python并发编程

    进程 相关概念 进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本 ...

  7. 【问题解决方案】从 Anaconda Prompt 或 Jupyter Notebook 终端进入Python后重新退出到命令状态

    从 Anaconda Prompt 或 Jupyter Notebook 终端进入Python后重新退出到命令状态 退出Python:exit() 或者 Ctrl+z 例子一枚 默认打开的是3.7,需 ...

  8. HDU 1089 到1096 a+b的输入输出练习

    http://acm.hdu.edu.cn/showproblem.php?pid=1089 Problem Description Your task is to Calculate a + b.T ...

  9. 阿里云CodePipeline vs Jenkins

    产品概述_产品简介_CodePipeline-阿里云 https://help.aliyun.com/document_detail/56512.html CodePipeline管理控制台https ...

  10. Windows10下安装VMware虚拟机并搭建CentOS系统环境

    转载: http://blog.51cto.com/10085711/2069270 操作系统 Windows 10专业版(64位) VMware虚拟机 产品:VMware® Workstation ...