【Codeforces Round 345 (Div 1) C】【并查集缩环+拓扑最长路】Table Compression nm矩形权值缩小大小关系不变

本文介绍了一种算法问题,即给定一组坐标点,通过特殊的方式计算不同点间的距离,并探讨了一个矩阵数值压缩的问题,目的是在保持相对大小关系不变的前提下,尽可能地减少矩阵中的数值种类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C. Watchmen
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Watchmen are in a danger and Doctor Manhattan together with his friend Daniel Dreiberg should warn them as soon as possible. There are n watchmen on a plane, the i-th watchman is located at point (xi, yi).

They need to arrange a plan, but there are some difficulties on their way. As you know, Doctor Manhattan considers the distance between watchmen i and j to be |xi - xj| + |yi - yj|. Daniel, as an ordinary person, calculates the distance using the formula .

The success of the operation relies on the number of pairs (i, j) (1 ≤ i < j ≤ n), such that the distance between watchman i and watchmen j calculated by Doctor Manhattan is equal to the distance between them calculated by Daniel. You were asked to compute the number of such pairs.

Input

The first line of the input contains the single integer n (1 ≤ n ≤ 200 000) — the number of watchmen.

Each of the following n lines contains two integers xi and yi (|xi|, |yi| ≤ 109).

Some positions may coincide.

Output

Print the number of pairs of watchmen such that the distance between them calculated by Doctor Manhattan is equal to the distance calculated by Daniel.

Examples
input
3
1 1
7 5
1 5
output
2
input
6
0 0
0 1
0 2
-1 1
0 1
1 1
output
11
Note

In the first sample, the distance between watchman 1 and watchman 2 is equal to |1 - 7| + |1 - 5| = 10 for Doctor Manhattan and  for Daniel. For pairs (1, 1)(1, 5) and (7, 5)(1, 5) Doctor Manhattan and Daniel will calculate the same distances.



#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1e6+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int n, m, T;
int a[N];
int f[N];
pair<int, int>b[N];
vector<int>w[N];
int ind[N];
int s[N];
int ans[N];
int find(int x)
{
	return f[x] == x ? x : f[x] = find(f[x]);
}
void merge(int x, int y)
{
	x = find(x);
	y = find(y);
	f[y] = x;
}
void ins(int x, int y)
{
	x = find(x);
	y = find(y);
	w[x].push_back(y);
	++ind[y];
}
void init()
{
	T = n*m;
	for (int i = 0; i < T; ++i)
	{
		scanf("%d", &a[i]);
		f[i] = i;
		w[i].clear();
		ind[i] = 0;
	}
}
void union_find()
{
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
		{
			int o = i*m + j;
			b[j] = MP(a[o], o);
		}
		sort(b, b + m);
		for (int j = 1; j < m; ++j)
		{
			if (b[j].first == b[j - 1].first)
			{
				int x = b[j].second;
				int y = b[j - 1].second;
				merge(x, y);
			}
		}
	}
	for (int j = 0; j < m; ++j)
	{
		for (int i = 0; i < n; ++i)
		{
			int o = i*m + j;
			b[i] = MP(a[o], o);
		}
		sort(b, b + n);
		for (int i = 1; i < n; ++i)
		{
			if (b[i].first == b[i - 1].first)
			{
				int x = b[i].second;
				int y = b[i - 1].second;
				merge(x, y);
			}
		}
	}
}
void connect()
{
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
		{
			int o = i*m + j;
			b[j] = MP(a[o], o);
		}
		sort(b, b + m);
		for (int j = 1; j < m; ++j)
		{
			if (b[j].first != b[j - 1].first)
			{
				int x = b[j].second;
				int y = b[j - 1].second;
				ins(y, x);
			}
		}
	}
	for (int j = 0; j < m; ++j)
	{
		for (int i = 0; i < n; ++i)
		{
			int o = i*m + j;
			b[i] = MP(a[o], o);
		}
		sort(b, b + n);
		for (int i = 1; i < n; ++i)
		{
			if (b[i].first != b[i - 1].first)
			{
				int x = b[i].second;
				int y = b[i - 1].second;
				ins(y, x);
			}
		}
	}
}
void topo()
{
	int top = 0;
	for (int i = 0; i < T; ++i)
	{
		ans[i] = 1;
		if (ind[i] == 0) s[++top] = i;
	}
	while (top)
	{
		int x = s[top--];
		for (int i = w[x].size() - 1; ~i; --i)
		{
			int y = w[x][i];
			gmax(ans[y], ans[x] + 1);
			if (--ind[y] == 0)s[++top] = y;
		}
	}
}
void print()
{
	for (int i = 0; i < T; ++i)
	{
		int x = find(i);
		ans[i] = ans[x];
	}
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
		{
			printf("%d ", ans[i*m + j]);
		}
		puts("");
	}
}
int main()
{
	while (~scanf("%d%d", &n,&m))
	{
		init();
		union_find();
		connect();
		topo();
		print();
	}
	return 0;
}
/*
【trick&&吐槽】
1,找不到错这么办?对拍!
2,缩点转移怎么快?建边!

【题意】
给你一个n*m的棋盘,1<=n,m,n*m<=1e6,每个点的数值都在[1,1e9]之间
我们想要把这个棋盘的数值尽可能向小压缩。
但是一些大小关系仍然要保持不变——
原来如果是相同关系,之后也要是相等关系。
原来如果是小于关系,之后也要是小于关系。
原来如果是大于关系,之后也要是大于关系。

让你输出被压缩后的最小矩阵

【类型】
第一步:缩环=> tarjan or 并查集
第二步:最长路=> bfs or 拓扑

【分析】
首先,这题一个很简单的猜想,就是放数,我们必然是从小往大一个个放数。
那么我的做法就是记录每行每列的最大数,然后逐渐确定接下来放数的最小值。
然而,这样的做法是有问题的,因为我们需要考虑数值相同的点。
如果两个点数值相同,且有行列对应关系,那么这两个点的大小关系是捆绑的。
比如——
412
443
444
我们放4的时候,如果是放左上角的4,那权值我们会选作3.
然而其受限制的捆绑关系要求,这个数值必须要填4= =

然后就GG了。
于是,我们要把权值相同的点缩点。
然后,再放数的时候,我们就有之前放的都比它小,这个数的权值可以确定。

缩点可以用并查集实现

【时间复杂度&&优化】
O(10nm about)

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值