The 2018 ACM-ICPC Asia Jiaozuo Regional Contest C. Supreme Command

The 2018 ACM-ICPC Asia Jiaozuo Regional Contest C. Supreme Command

题目链接

http://codeforces.com/gym/102028/problem/C

题目大意

给你一个 $n$ 行 $n$ 列的棋盘,保证每行每列都有且仅有一个棋子。有四种操作,向四个方向移动所有棋子,如果无法移动则停留在原地。两种询问,问某个棋子当前的位置,和当前情况下有多少个重叠再一起的棋子对。

题目分析

注意到每一行每一列都只有一个棋子,则会产生一个很有意思的性质:所有的棋子如果出现合并的情况必定存在它的 $x$ 坐标等于所有棋子的最小值或最大值且 $y$ 坐标也是所有棋子的最小值或最大值。那么一共有四种情况。首先考虑如何维护所有棋子的坐标。由于所有棋子的初始行列坐标都是唯一对应的,因此可以快速将所有点按照行列坐标分别排序。分别维护所有点的行列坐标,每次将所有能移动到边界的行列都合并,记录合并到第几个点即可。由于在最小值和最大值中间的每一个值上都会有一个点,因此可以很轻松的维护点的坐标。再考虑维护重叠的点。由于所有的点一定是在四个角处才能合并因此只需要维护四种情况。而当所有点都合并成一个的时候,这四种情况会合并,维护即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 3e5 + 10;

int n, m, t;

pair <int, int> point[maxn];

int c[2][maxn];

int treen[2][maxn];
	
/*
x y
1 1 1
1 2 2
2 1 3
2 2 4
*/
	
int getn(int x, int y, int d){
	int ret[4][4];
	ret[1][1] = 1;
	ret[1][2] = 2;
	ret[2][1] = 3;
	ret[2][2] = 4;
	ret[3][1] = 1;
	ret[3][2] = 2;
	ret[1][3] = 1;
	ret[2][3] = 3;
	ret[3][3] = 1;
	if(d){
		return ret[y][x];
	}else{
		return ret[x][y];
	}
}

struct unionset {
	int fa[maxn];
	long long son[maxn];
	int cnt;
	
	int find(int x){
		if(fa[x] != x){
			fa[x] = find(fa[x]);
		}
		
		return fa[x];
	}
	
	int join(int x, int y){
		int ra = find(x);
		int rb = find(y);
		
		if(ra != rb){
			fa[ra] = rb;
			son[rb] += son[ra];
		}
		
		return 0;
	}
	
	long long getans(){
		int i, j;
		long long ret = 0;
		
		for(i=n+1;i<=n+4;i++){
			if(find(i) == i and son[i] > 1){
				ret += son[i] * (son[i] - 1) / 2;
			}
		}
		
		return ret;
	}
	
	int init(){
		int i, j;
		
		for(i=1;i<=n+4;i++){
			fa[i] = i;
			son[i] = (i <= n ? 1 : 0);
		}
		
		return 0;
	}
};

unionset s;

struct sttree {
	int mx, mn, delta;
	int l, r;
	
	int query(int x){
		if(x <= l){
			return mn;
		}else if(x < r){
			return delta + x;
		}else{
			return mx;
		}
	}
	
	int update(int x, int d){
		if(x > 0){
			if(mx + x <= n){
				delta += x;
				mx += x;
				mn += x;
			}else{
				if(mn + x >= n){
					l = n;
					r = 1;
					mx = n;
					mn = n;
					if(c[d][1] != 3){
						if(c[!d][1] != 3){
							for(int i=1;i<=n;i++){
								c[d][i] = 3;
								if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
									s.join(treen[d][i], n + getn(3, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
								}
							}
						}else{
							for(int i=1;i<=n;i++){
								c[d][i] = 3;
								if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
									s.join(treen[d][i], n + getn(3, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
								}
							}
							s.join(n + 1, n + 3), s.join(n + 2, n + 4);
							s.join(n + 1, n + 2), s.join(n + 3, n + 4);
						}
					}
				}else{
					int p = r - (mx - (n - x));
					int u = r;
					delta += x;
					mn += x;
					mx = n;
					r = p;
					for(int i=p;i<u;i++){
						c[d][i] = 2;
						if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
							s.join(treen[d][i], n + getn(2, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
						}
					}
				}
			}
		}else{
			if(mn + x >= 1){
				delta += x;
				mx += x;
				mn += x;
			}else{
				if(mx + x <= 1){
					mx = 1;
					mn = 1;
					l = n;
					r = 1;
					if(c[d][1] != 3){
						if(c[!d][1] != 3){
							for(int i=1;i<=n;i++){
								c[d][i] = 3;
								if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
									s.join(treen[d][i], n + getn(3, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
								}
							}
						}else{
							for(int i=1;i<=n;i++){
								c[d][i] = 3;
								if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
									s.join(treen[d][i], n + getn(3, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
								}
							}
							s.join(n + 1, n + 3), s.join(n + 2, n + 4);
							s.join(n + 1, n + 2), s.join(n + 3, n + 4);
						}
					}
				}else{
					int p = l + ((1 - x) - mn);
					int u = l;
					delta += x;
					mn = 1;
					mx += x;
					l = p;
					for(int i=u+1;i<=p;i++){
						c[d][i] = 1;
						if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
							s.join(treen[d][i], n + getn(1, c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
						}
					}
				}
			}
		}
		
		return 0;
	}
	
	int init(){
		mx = n;
		mn = 1;
		l = 1;
		r = n;
		delta = 0;
		
		return 0;
	}
};

sttree treex;
sttree treey;

int read(){
	int x = 0;
	char ch = getchar();
	
	while('0' > ch or ch > '9'){
		ch = getchar();
	}
	
	while('0' <= ch and ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	
	return x;
}

int main(){
	int i, j;
	int x, y;
	char op;
	int d;
	
	t = read();
	
	while(t--){
		n = read();
		m = read();
		
		s.init();
		
		for(i=1;i<=n;i++){
			x = read();
			y = read();
			point[i] = make_pair(x, y);
			treen[0][x] = treen[1][y] = i;
			c[0][i] = c[1][i] = 0;
		}
		
		c[0][1] = c[1][1] = 1;
		c[0][n] = c[1][n] = 2;
		
		d = 0,i = 1;
		if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
			s.join(treen[d][i], n + getn(c[d][i], c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
		}
		
		d = 0,i = n;
		if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
			s.join(treen[d][i], n + getn(c[d][i], c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
		}
		
		d = 1,i = 1;
		if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
			s.join(treen[d][i], n + getn(c[d][i], c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
		}
		
		d = 1,i = n;
		if(c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)] != 0){
			s.join(treen[d][i], n + getn(c[d][i], c[!d][(d ? point[treen[d][i]].first : point[treen[d][i]].second)], d));
		}
		treex.init();
		treey.init();
		
		while(m--){
			scanf(" %c", &op);
			
			if(op == '!'){
				printf("%lld\n", s.getans());
			}else{
				x = read();
				if(op == 'L'){
					treey.update(-x, 1);
				}else if(op == 'R'){
					treey.update(x, 1);
				}else if(op == 'U'){
					treex.update(-x, 0);
				}else if(op == 'D'){
					treex.update(x, 0);
				}else if(op == '?'){
					printf("%d %d\n", treex.query(point[x].first), treey.query(point[x].second));
				}
			}
		}
	}
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据