【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
output
input
output
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)
*/
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)
*/
相关文章推荐
- 【Educational Codeforces Round 1A】【水题】Tricky Sum 1~n之和减去2的幂
- 【Educational Codeforces Round 1B】【字符串平移 水题】Queries on a String 字符串平移水题
- 【Educational Codeforces Round 1C】【计算几何-极角排序 atan2 long double】Nearest vectors 平面图上原点引出角度最小的两个
- 【Educational Codeforces Round 1D】【DFS 联通块打标记法】Igor In the Museum 联通块内墙的面数
- 【Educational Codeforces Round 1E】【动态规划-多维DP】Chocolate Bar 矩形巧克力掰开吃的最小成本
- 【HDU5222 2015赛码冠军杯I】【并查集找双连通 + tarjan求强连通】Exploration 双向边只能走一边是否图上存在环
- 【Codeforces Round 299 (Div 2)D】【KMP 本质是最前与最后匹配】Tavas and Malekas 长度为n的匹配串被模板串多位点覆盖的匹配串个数
- 【Codeforces Round 333 (Div 2)A 】【水题 简单进制模拟】Two Bases 不同进制数比大小
- 【Codeforces Round 333 (Div 2)B】【贪心 多指针】Approximating a Constant Range 给定数组 相邻元素波动为1 求差值不超1的最长序连续子序列
- 【Codeforces Round 333 (Div 2)C】【最短路】The Two Routes 完全图两种双向边的最小最大距离
- 【Codeforces Round 333 (Div 2)D】【线段树 or ST-RMQ 初始化78msAC】Lipshitz Sequence 若干区间询问所有子区间的答案和
- 【Codeforces Round 333 (Div 2)E】【期望DP概率做法 树状数组转前缀和】Kleofáš and the n-thlon n场比赛m个人获得总名次的期望
- 【Codeforces Testing Round 12A】【讨论 边界元素映射】Divisibility 区间范围内k倍数的数的个数
- 【Codeforces Testing Round 12B】【贪心】Restaurant 选取数量最多的不覆盖区间数
- 【Codeforces Testing Round 12C】【DP 树状数组优化】Subsequences n个不同数,长度为m的LIS数
- 【Educational Codeforces Round 2B】【map or 二分查找】Queries about less or equal elements b[]中的每个数比a[]中多少数大
- 【Educational Codeforces Round 2C】【贪心】最少修改数下得到字典序尽可能小回文串
- 【Educational Codeforces Round 2D】【计算几何 圆面积交 模板】Area of Two Circles' Intersection
- 【Educational Codeforces Round 2E】【STL-map 启发式合并 or 线段树动态开节点 】Lomsat gelral 一棵树每点一个颜色问每个节点子树的颜色众数之和
- 【Codeforces Beta Round 2A】【模拟 map 有map的java实现哦】Winner 第一个达到最终最高分的人名