北京集训的第一天,我完美爆零......
这其中的经历,十分有趣呢。
T1:
这题一看就是先猜一个性质然后利用他去求解。
如果我们知道怎么插入,怎么判定的话,可以线段树分治的说。
然后我猜了一个结论:如果稳定,则一定有一个x的四联通块能同时通向上下左右边界。
乍一看是对的,实际上这个东西充分,但不必要。
考虑3*3的网格图,我们染色左下角三个点,再染色右上角三个点,结果应该是稳定的。
然后这个算法就错了。
问题是由于我太菜了,故考场上并没有想到这个反例......
正解的确是线段树分治,然而他是用角度推的。
考虑对于一个四边形的四个定点,每个点在左上角的那个角,显然对角线的角和相同。
而如果一个格子为x,则他右下角和左上角的角度均为90度,相当于让另外两个角必须满足某些条件。
而如果这个条件让整个图都被限制的话,显然就固定了。
现在我们可以做什么?O(nmq)暴力。
然而正解要更加优美:
显然我们可以用第一行的所有角度和第一列的所有角度算出所有角,所以限制就相当于是行列连边。
经典的二分图模型啦。
然后用可回退并查集维护是否左右行列都在一个联通块里就好了QwQ。
考场爆零代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #define debug cout 7 using namespace std; 8 const int maxn=9e6+1e2,maxl=3e3+1e2,maxq=1e5+1e2; 9 const int dx[]={1,-1,0,0},dy[]={0,0,1,-1}; 10 11 char in[maxl][maxl],now[maxl][maxl]; 12 int tim[maxl][maxl],ans[maxq]; 13 int l[maxq<<3],r[maxq<<3],lson[maxq<<3],rson[maxq<<3],cnt; 14 int fa[maxn],siz[maxn],sta[maxn]; 15 int n,m,q; 16 int pp; 17 18 struct ONode { 19 int x,y; 20 }; 21 vector<ONode> ns[maxq<<3]; 22 23 struct MemNode { 24 int *dst,val; 25 MemNode() {} 26 MemNode(int &x) { dst = &x , val = x; } 27 inline void res() { 28 *dst = val; 29 } 30 }stk[maxn]; 31 int top; 32 33 inline int findfa(int x) { 34 return fa[x] == x ? x : findfa(fa[x]); 35 } 36 inline bool merge(int x,int y) { 37 x = findfa(x) , y = findfa(y); 38 if( x == y ) return 0; 39 if( siz[x] < siz[y] ) swap(x,y); 40 if( pp != 1 ) stk[++top] = MemNode(siz[x]) , stk[++top] = MemNode(fa[y]) , stk[++top] = MemNode(sta[x]); 41 fa[y] = x , siz[x] += siz[y] , sta[x] |= sta[y]; 42 return sta[x] == 15; 43 } 44 45 inline void reset(int ltop) { 46 while( top > ltop ) stk[top].res() , --top; 47 } 48 inline int cov(int x,int y) { 49 return m * --x + y; 50 } 51 inline int operat(int x,int y) { 52 int ret = 0; 53 now[x][y] = 'x'; 54 ret |= ( sta[findfa(cov(x,y))] == 15 ); 55 for(int i=0;i<4;i++) { 56 const int tx = x + dx[i] , ty = y + dy[i]; 57 if( 0 < tx && tx <= n && 0 < ty && ty <= m && now[tx][ty] == 'x' ) ret |= merge(cov(x,y),cov(tx,ty)); 58 } 59 return ret; 60 } 61 62 inline void build(int pos,int ll,int rr) { 63 l[pos] = ll , r[pos] = rr; 64 if( ll == rr ) return; 65 const int mid = ( ll + rr ) >> 1; 66 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+1,rr); 67 } 68 inline void insert(int pos,int ll,int rr,const ONode &o) { 69 if( ll <= l[pos] && r[pos] <= rr ) { 70 ns[pos].push_back(o); 71 return; 72 } const int mid = ( l[pos] + r[pos] ) >> 1; 73 if( rr <= mid ) insert(lson[pos],ll,rr,o); 74 else if( ll > mid ) insert(rson[pos],ll,rr,o); 75 else insert(lson[pos],ll,rr,o) , insert(rson[pos],ll,rr,o); 76 } 77 inline void dfs(int pos,int stable) { 78 pp = pos; 79 const int memtop = top; 80 for(unsigned i=0;i<ns[pos].size();i++) stable |= operat(ns[pos][i].x,ns[pos][i].y); 81 if( l[pos] == r[pos] ) { 82 ans[l[pos]] = stable; 83 } 84 else dfs(lson[pos],stable) , dfs(rson[pos],stable); 85 if( pos != 1 ) { 86 reset(memtop); 87 for(unsigned i=0;i<ns[pos].size();i++) now[ns[pos][i].x][ns[pos][i].y] = 0; 88 } 89 } 90 91 int main() { 92 static int q; 93 scanf("%d%d%d",&n,&m,&q); 94 for(int i=1;i<=n;i++) { 95 scanf("%s",in[i]+1); 96 for(int j=1;j<=m;j++) if( in[i][j] == 'x' ) tim[i][j] = 1; 97 } 98 build(cnt=1,1,q+1); 99 for(int i=1,x,y;i<=q;i++) { 100 scanf("%d%d",&x,&y); 101 if( tim[x][y] ) { 102 insert(1,tim[x][y],i,(ONode){x,y}) , tim[x][y] = 0; 103 } 104 else tim[x][y] = i+1; 105 } 106 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if( tim[i][j] ) { 107 insert(1,tim[i][j],q+1,(ONode){i,j}); 108 } 109 for(int i=1;i<=n;i++) 110 for(int j=1;j<=m;j++) { 111 const int c = cov(i,j); 112 fa[c] = c , siz[c] = 1; 113 if( i == 1 ) sta[c] |= 1; 114 if( j == 1 ) sta[c] |= 2; 115 if( i == n ) sta[c] |= 4; 116 if( j == m ) sta[c] |= 8; 117 } 118 dfs(1,0); 119 for(int i=1;i<=q+1;i++) puts(ans[i]?"S":"U"); 120 return 0; 121 }