您的位置:首页 > 大数据 > 人工智能

【模拟+hash+并查集】2014 Multi-University Training Contest 2|HDU_4879 ZCC loves march

2014-07-26 19:10 429 查看
原题直通车:HDU_4879 ZCC loves march

题意概述:在m*m(m<=10^18)的矩阵中有n(n<=10^5)个数(1~n),有k(k<=10^5)次操作,有以下两种操作:

1、将一个数i在同一行或同一列上移动d个单位

2、将与数i在同一行或同一列的所有数都移到i所在的位置,并输出所有(xi-xj)^2+(yi-yj)^2的和

分析:

1、因为只有移动和操作,所以占用到的坐标数最多为n+k个,所以用一个map将每个坐标映射到一个数。

2、对于操作2,为了便于查到每一行、每一列中有多少个数,所以用map映射到每一行、列分别一个set集合

3、放到每个set集合中的并不是n个数,而是每一个坐标的映射,因为每个坐标可能有多个数,但映射只有一个(理论上是),只要记录每个坐标上有多少个数即可,因为结果只与坐标有关,与n个数无关,以此避免TLE和MLE。

4、一个数只对应一个坐标,移动的时候,可以直接看成坐标的变化,也就是对应坐标映射的变化,所以只需用一个next数据记录移动的位置,数的数量直接相加即可。

5、虽然经过操作2之后,坐标中已经没有数了,但是后面可能会用到相应的next,所以经过了操作2的坐标要重新开辟一个映射,才不会和后面进行操作1时移动到这种坐标的数相应的next冲突。

附:2014 Multi-University Training Contest 2--by 镇海中学
解题报告

参考代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int maxn = 1e5+100;
const int mod = 1e9+7;

int fa[maxn], num[maxn<<1], next[maxn<<1];
long long x[maxn<<1], y[maxn<<1];

typedef long long LL;
typedef pair<LL, LL> pl;
typedef map< pl, int > map_pl;
typedef map< LL, set<int> > map_LL;
typedef pair< map_LL::iterator, map_LL::iterator > pll;

map_LL mx, my;
map_pl M;

int n;
LL m, len, ans, d;

void Input() {
for(int i=1; i<=n; ++i) {
long long xx, yy;
scanf("%I64d%I64d", &xx, &yy);
pl p = make_pair(xx, yy);
if(M[p] == 0) {
x[len] = xx, y[len] = yy, num[len] = 0, next[len] = len;

pll px = mx.equal_range(xx), py = my.equal_range(yy);
if(px.first == px.second) { set<int>s; mx[xx] = s; } //还没有映射的集合
if(py.first == py.second) { set<int>s; my[yy] = s; }
mx[xx].insert(len), my[yy].insert(len);

M[p] = len++;
}
num[M[p]]++;
fa[i] = M[p];
}
}

int get_end(int rt) { //寻找最终的移动位置
return next[rt] == rt ? rt : (next[rt] = get_end(next[rt]));
}

int main() {
while(~scanf("%d%I64d", &n, &m)) {
len = 1, ans = 0;
mx.clear(), my.clear(), M.clear();
Input();
int k, o; scanf("%d", &k);
while(k--) {
char op[5];
scanf("%s%d", op, &o);
o ^= ans;
int rt = get_end(fa[o]);
fa[o] = rt; //指向移动的位置

pl p = make_pair(x[rt], y[rt]);
if(op[0] == 'Q') {
ans = 0;
set<int>sx = mx[x[rt]], sy = my[y[rt]]; //同行、同列的坐标
set<int>::iterator it;
for(it=sx.begin(); it!=sx.end(); ++it)
if((*it) != rt) {
int ne = get_end(*it);
long long u = (y[ne] - y[rt] + mod) % mod;
u = ( (u * u)%mod )*num[ne] %mod;
ans = (ans + u) % mod;
my[y[ne]].erase(ne);
num[rt] += num[ne], num[ne] = 0, next[ne] = rt;
M[make_pair(x[ne], y[ne])] = 0;  // 对应的位置不能再用,因为可能有其它的next指向这里
}
for(it=sy.begin(); it!=sy.end(); ++it)
if((*it) != rt) {
int ne = get_end(*it);
long long u = (x[ne] - x[rt] + mod) % mod;
u = ( (u * u)%mod )*num[ne] %mod;
ans = (ans + u) % mod;
my[x[ne]].erase(ne);
num[rt] += num[ne], num[ne] = 0, next[ne] = rt;
M[make_pair(x[ne], y[ne])] = 0; // 对应的位置不能再用,因为可能有其它的next指向这里
}
printf("%I64d\n", ans);
continue;
}
scanf("%I64d", &d);
long long xx = x[rt], yy = y[rt];
if(op[0] == 'U') xx -= d;
if(op[0] == 'D') xx += d;
if(op[0] == 'L') yy -= d;
if(op[0] == 'R') yy += d;
num[rt]--;
p = make_pair(xx, yy);
if(M[p] == 0) {
x[len] = xx, y[len] = yy, num[len] = 0, next[len] = len;
M[p] = len++;
}
fa[o] = M[p]; //o被移动到M[p]坐标,直接改变坐标指向
num[M[p]]++;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐