• [IOI2018] seats 排座位(线段树)


    Solution

    • 显然同样大小的子矩阵中,符合条件的最多一个
    • 考虑判断\([0...i-1]\)的数是否构成一个矩形:
    • \([0...i-1]\)所在格点染成黑色,剩下的染成白色
    • 将边界以外的格点看作白色
    • 如果\([0...i-1]\)的数是否构成一个矩形,那么这\(i\)个点中:
    • \((1)\) “左上都是白点”的黑点数记为\(x\)\(x=1\)
    • \((2)\) “上下左右4个点中,是黑点的大于等于2个”的白点记为\(y\)\(y=0\)
    • 满足\((1)\),就满足了这\(i\)个点处于同一连通块
    • 满足\((2)\),就满足了这\(i\)个点构成一个矩形,不满足则说明存在“拐角”,例如(下图中\(B\)为满足\((2)\)的白点):
      \(WB\)
      \(WW\)
    • 如果只满足\((2)\),不满足\((1)\),可能构成多个矩形
    • 因为不存在\(x=0\)\(y=1\)的情况(实际上是没有\(x=0\)的情况)
    • 所以满足\(x+y=1\)即合法
    • 线段树维护对于每个\(i\)\(x+y\)的值
    • 并且维护区间最小值及最小值个数(最小值不可能为0)
    • 对于每个点\(u\),一定是先白后黑
    • \(u\)为白点的最晚时刻为\(l[u]\),为黑点的最早时刻为\(r[u]\)
    • \(u\)周围\(4\)个点的\(r\)次小值\(z\)(如果点越界,\(r=inf\)
    • 它作为满足\((2)\)的点的时段即\([z,l[u]]\)(注意特判\(z>l[u]\)的情况)
    • 那么在线段树上给\([z,l[u]]+1\)
    • \(u\)左上的\(l\)的最小值为\(t\)(如果点越界,\(l=HW-1\)
    • 它作为满足\((1)\)的点的时段即\([r[u],t]\)(注意特判\(r[u]>t\)的情况)
    • 那么在线段树上给\([r[u],t]+1\)
    • 每次交换时,见掉两个点\(a,b\)及他们周围\(4\)个点(共\(O(10)\)个点)在两点交换前的贡献,交换\(a,b\),加上这些点在两点交换后的贡献
    • 注意如果\(10\)个点中有重复的,不可以重复加减贡献
    • 要记录矩阵中每个位置上的数是什么,以及每个数所在位置是什么

    Code

    注:由于个人习惯,以下程序中编号为\([1...HW]\)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define p2 p << 1
    #define p3 p << 1 | 1
    
    template <class t>
    inline void read(t & res)
    {
    	char ch;
    	while (ch = getchar(), !isdigit(ch));
    	res = ch ^ 48;
    	while (ch = getchar(), isdigit(ch))
    	res = res * 10 + (ch ^ 48);
    }
    
    const int e = 1e6 + 5, dx[] = {-1, 0, 1, 0, 0}, dy[] = {0, -1, 0, 1, 0}, inf = 0x3f3f3f3f;
    struct point
    {
    	int x, y;
    }a[e];
    int val[e * 4], cnt[e * 4], n, m, add[e * 4], q, tmp, id[e], pos[e], vis[e], now;
    
    inline void collect(int p)
    {
    	if (val[p2] == val[p3])
    	{
    		val[p] = val[p2];
    		cnt[p] = cnt[p2] + cnt[p3];
    	}
    	else if (val[p2] < val[p3])
    	{
    		val[p] = val[p2];
    		cnt[p] = cnt[p2];
    	}
    	else
    	{
    		val[p] = val[p3];
    		cnt[p] = cnt[p3];
    	}
    }
    
    inline void pushdown(int p)
    {
    	if (add[p])
    	{
    		add[p2] += add[p];
    		add[p3] += add[p];
    		val[p2] += add[p];
    		val[p3] += add[p];
    		add[p] = 0;
    	}
    }
    
    inline void build(int l, int r, int p)
    {
    	if (l == r)
    	{
    		cnt[p] = 1;
    		return;
    	}
    	int mid = l + r >> 1;
    	build(l, mid, p2);
    	build(mid + 1, r, p3);
    	collect(p);
    }
    
    inline void update(int l, int r, int s, int t, int v, int p)
    {
    	if (l == s && r == t)
    	{
    		val[p] += v;
    		add[p] += v;
    		return; 
    	}
    	pushdown(p);
    	int mid = l + r >> 1;
    	if (t <= mid) update(l, mid, s, t, v, p2);
    	else if (s > mid) update(mid + 1, r, s, t, v, p3);
    	else
    	{
    		update(l, mid, s, mid, v, p2);
    		update(mid + 1, r, mid + 1, t, v, p3);
    	}
    	collect(p);
    }
    
    inline void upt(int l, int r, int v)
    {
    	l = max(l, 1);
    	r = min(r, tmp);
    	update(1, tmp, l, r, v, 1);
    }
    
    inline int get(int x, int y)
    {
    	return (x - 1) * m + y;
    }
    
    inline void join(int x, int y, int opt)
    {
    	vis[get(x, y)] = now;
    	int i, p[4];
    	for (i = 0; i < 4; i++)
    	{
    		int xx = dx[i] + x, yy = dy[i] + y;
    		if (xx < 1 || yy < 1 || xx > n || yy > m) p[i] = inf;
    		else p[i] = id[get(xx, yy)];
    	}
    	sort(p, p + 4);
    	int tim = id[get(x, y)] - 1;
    	if (p[1] <= tim) upt(p[1], tim, opt);
    	tim++;
    	for (i = 0; i < 2; i++)
    	{
    		int xx = dx[i] + x, yy = dy[i] + y;
    		if (xx < 1 || yy < 1 || xx > n || yy > m) p[i] = inf;
    		else p[i] = id[get(xx, yy)] - 1;
    	}
    	sort(p, p + 2);
    	if (tim <= p[0]) upt(tim, p[0], opt);
    }
    
    inline void change(int x, int y, int opt)
    {
    	int i;
    	for (i = 0; i < 5; i++)
    	{
    		int xx = x + dx[i], yy = y + dy[i];
    		if (xx < 1 || yy < 1 || xx > n || yy > m || vis[get(xx, yy)] == now) continue;
    		join(xx, yy, opt);
    	}
    }
    
    int main()
    {
    	read(n); read(m); read(q);
    	int i, u, v;
    	tmp = n * m;
    	for (i = 1; i <= tmp; i++)
    	{
    		read(a[i].x);
    		a[i].x++;
    		read(a[i].y);
    		a[i].y++;
    		pos[i] = get(a[i].x, a[i].y);
    		id[get(a[i].x, a[i].y)] = i;
    	}
    	build(1, tmp, 1);
    	for (i = 1; i <= tmp; i++) join(a[i].x, a[i].y, 1);
    	while (q--)
    	{
    		read(u);
    		read(v);
    		u++;
    		v++;
    		now++;
    		change(a[u].x, a[u].y, -1);
    		change(a[v].x, a[v].y, -1);
    		int idx = u, idy = v, px = pos[idx],
    		py = pos[idy];
    		id[px] = idy;
    		id[py] = idx;
    		pos[idx] = py;
    		pos[idy] = px;
    		now++;
    		change(a[u].x, a[u].y, 1);
    		change(a[v].x, a[v].y, 1);
    		swap(a[u].x, a[v].x);
    		swap(a[u].y, a[v].y);
    		printf("%d\n", cnt[1]);
    	}
    	return 0; 
    }
    
  • 相关阅读:
    Check the string
    最简单的
    第七届ACM程序设计竞赛 (SDIBT)
    Cutie Pie
    CSS3 :nth-of-type() 与 nth-child()选择器
    Ajax 完整教程 转载地址:http://www.cnblogs.com/Garden-blog/archive/2011/03/11/1981778.html(转)
    排序:二元选择排序
    排序:堆排序
    排序:直接插入排序 稳定 n*n
    排序:冒泡和改进
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12196341.html
Copyright © 2020-2023  润新知