您的位置:首页 > 理论基础 > 数据结构算法

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

2016-03-08 19:07 465 查看
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
;
int f
;
pair<int, int>b
;
vector<int>w
;
int ind
;
int s
;
int ans
;
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 拓扑

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

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

缩点可以用并查集实现

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

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐