sol:
早上被吊锤,还以为发现了性质写了个70分,出来10分
考虑这题用高消做,给每个正方形右下角的角度数弄成90+x[i][j]的形式。
那么显然可以得到4个相邻方格的方程。然后把上一个方程代到下一个方程里,不停的做,就可以得到若干个x1,1-xi,1-x1,i+xi,j=0的方程。这样的话其实我们只要求出一行一列的话,就可以得到所有的解了。显然如果解唯一的话就是S否则为U。那我们发现如果xi,j是‘.’的话,这个方程可以舍弃掉,他并不对我们求解第一行第一列有用。如果x1,1是x的话,那么x1,1=0.这个方程就变成了xi,1=x1,i的形式,这个关系就非常好了,我们考虑如果x1,1不是0怎么办,我们发现完全可以把1,1挪一挪,用其他的x来当做中心点,且显然问题等价。
那么我们的问题就变成求解某行某列,然后给出若干xk,i=xj,k的关系,考虑这个东西只要知道一者另一者就知道了,所以把这种关系当成边,求生成树然后看能否包含所有点即可。那么点数就是n+m的。
但是这个问题是动态的,也就是说边是有加入删除的,那么一条边就有若干个出现时间的区间,那么我们枚举当前的时间,然后边按照l,r排序,用lct维护一下双瓶颈生成树即可。那么我们关心的有2个地方,当前树是否包含n+m个点,当前树边最小的l是否>当前时间。前面的我用lct维护子树信息或者用堆做都可以。后面的用双堆维护即可。
但是一开始的边数有3000^2,这就很gg了。但是考虑到会变化的边只有q条,我们把不变的边用并查集并一下,然后把一个集合的点提前连边即可。
lct真的有点小麻烦,别人写线段树分治好像特别快。
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
int n,m,p;
const int N=1e6;
int lc[N],rc[N],ans[N],fa[N],val[N],real[N];
int sum1[N],sum2[N];
int father[N];
int en;
struct ed
{
int x,y,l,r;
friend inline bool operator <(const ed &a,const ed &b)
{
return a.l<b.l||a.l==b.l&&a.r<b.r;
}
}edge[N];
inline int find(int x)
{
return father[x]==x?x:father[x]=find(father[x]);
}
inline void updata(int x)
{
sum1[x]=sum1[lc[x]]+sum1[rc[x]]+sum2[x]+real[x];
if(val[ans[lc[x]]]<val[ans[rc[x]]]) ans[x]=ans[lc[x]];
else ans[x]=ans[rc[x]];
if(val[ans[x]]>val[x]) ans[x]=x;
}
inline void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=lc[y]==x?rc[x]:lc[x];
if(b) fa[b]=y;
fa[x]=z;fa[y]=x;
if(z)
{
if(lc[z]==y) lc[z]=x;
if(rc[z]==y) rc[z]=x;
}
if(lc[y]==x) rc[x]=y,lc[y]=b;
else lc[x]=y,rc[y]=b;
updata(y);
}
inline bool is_root(int x)
{
return lc[fa[x]]!=x&&rc[fa[x]]!=x;
}
bool rev[N];
inline void tag_rev(int x)
{
rev[x]=!rev[x];
swap(lc[x],rc[x]);
}
inline void tag_down(int x)
{
if(rev[x])
{
tag_rev(lc[x]);
tag_rev(rc[x]);
rev[x]=0;
}
}
int sta[N];
inline void splay(int x)
{
sta[sta[0]=1]=x;
for(int y=x;!is_root(y);y=fa[y]) sta[++sta[0]]=fa[y];
while(sta[0]) tag_down(sta[sta[0]--]);
while(!is_root(x))
{
if(!is_root(fa[x]))
{
if((lc[fa[x]]==x)==(lc[fa[fa[x]]]==fa[x])) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
updata(x);
}
inline void access(int q)
{
for(int p=0;q;p=q,q=fa[q])
{
splay(q);
sum2[q]+=sum1[rc[q]];
rc[q]=p;
sum2[q]-=sum1[rc[q]];
updata(q);
}
}
inline void make_root(int x)
{
access(x);
splay(x);
tag_rev(x);
}
inline void cut(int x,int y)
{
make_root(x);
access(y);
splay(x);
rc[x]=fa[y]=0;
updata(x);
}
inline void link(int x,int y)
{
make_root(x);
access(y);
splay(y);
fa[x]=y;
sum2[y]+=sum1[x];
updata(y);
}
const int M=3100;
bool vis[M][M];
inline void unit(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) father[fy]=fx;
}
inline int find_rt(int x)
{
access(x);
splay(x);
tag_down(x);
while(lc[x])
{
x=lc[x];
tag_down(x);
}
return x;
}
vector<int> q[M][M];
char sr[M][M];
int point;
struct cc
{
int x,y;
}v[N];
struct P
{
int x;
friend inline bool operator <(const P &a,const P &b)
{
return a.x>b.x;
}
};
priority_queue<P> aa,ab;
inline int top()
{
while(!aa.empty()&&!ab.empty()&&aa.top().x==ab.top().x) aa.pop(),ab.pop();
return aa.top().x;
}
int main()
{
// freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;++i)
{
scanf("%s",sr[i]+1);
for(int j=1;j<=m;++j)
if(sr[i][j]=='x') q[i][j].push_back(0);
}
for(int i=1;i<=p;++i)
{
int x,y;
scanf("%d%d",&x,&y);
vis[x][y]=1;
q[x][y].push_back(i);
}
for(int i=0;i<=n+m;++i) real[i]=1,father[i]=i,val[i]=1e9;
real[n+1]=real[0]=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(!vis[i][j])
{
if(sr[i][j]=='x')
unit(i,j+n);
}
else if(q[i][j].size())
{
if(q[i][j].size()&1) q[i][j].push_back(p+1);
for(int k=0;k<q[i][j].size();k+=2)
edge[++en]=(ed){i,j+n,q[i][j][k],q[i][j][k+1]-1};
}
for(int i=1;i<=n+m;++i)
{
int t=find(i);
if(t!=i)
edge[++en]=(ed){i,t,0,p};
}
sort(edge+1,edge+1+en);
point=n+m;
int i=1;
for(int j=0;j<=p;++j)
{
for(;edge[i].l<=j&&i<=en;++i)
{
int x,y,z;
x=edge[i].x;
y=edge[i].y;
z=edge[i].r;
if(find_rt(x)!=find_rt(y))
{
val[++point]=z;
updata(point);
v[point].x=x;
v[point].y=y;
link(x,point);
link(point,y);
aa.push((P){z});
}
else
{
make_root(x);
access(y);
splay(x);
if(val[ans[x]]<z)
{
int t=ans[x];
cut(v[t].x,t);
cut(v[t].y,t);
val[++point]=z;
updata(point);
v[point].x=x;
v[point].y=y;
link(x,point);
link(point,y);
ab.push((P){val[t]});
aa.push((P){z});
}
}
}
make_root(1);
splay(1);
if(sum1[1]!=n+m-1) printf("U\n");
else
{
if(top()<j) printf("U\n");
else printf("S\n");
}
}
}