2014 Multi-University Training Contest 2 - 1008 (ZCC loves march)

http://acm.hdu.edu.cn/showproblem.php?pid=4879

ZCC loves march

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 130712/130712 K (Java/Others)
Total Submission(s): 762    Accepted Submission(s): 164


Problem Description
On a m*m land stationed n troops, numbered from 1 to n. The i-th troop's position can be described by two numbers (xi,yi) (1<=xi<=m,1<=yi<=m). It is possible that more than one troop stationed in the same place.
Then there are t minutes, in each minute one of the following two events will occur:
(1)the x-th troop moves towards a direction( Up(U) Down(D) Left(L) Right(R))for d units;(You can suppose that the troops won't move out of the boundary)
(2)the x-th troop needs to regroup the troops which stations in the same row or column with the x-th troop. That is, these troops need to move to the x-th troop's station.
Suggest the cost of i-th troop moving to the j-th troop is (xi-xj)^2+(yi-yj)^2, every time a troop regroups, you should output the cost of the regrouping modulo 10^9+7.
 

 

Input
The first line: two numbers n,m(n<=100000,m<=10^18)
Next n lines each line contain two numbers xi,yi(1<=xi,yi<=m)
Next line contains a number t.(t<=100000)
Next t lines, each line's format is one of the following two formats:
(1)S x d, S∈{U,L,D,R}, indicating the first event(1<=x<=n,0<=d<m)
(2)Q x, indicating the second event(1<=x<=n)
In order to force you to answer the questions online, each time you read x', x=x'⊕lastans("⊕" means "xor"), where lastans is the previous answer you output. At the beginning lastans=0. 
 

 

Output
Q lines, i-th line contain your answer to the i-th regrouping event.(modulo 10^9+7)
 

 

Sample Input
5 3 1 3 2 1 2 2 2 3 3 2 6 Q 1 L 0 2 L 5 2 Q 5 R 3 1 Q 3
 

 

Sample Output
1 1 7
Hint
The input after decode: Q 1 L 1 2 L 4 2 Q 4 R 2 1 Q 2
 

 

Author
镇海中学
 

 

Source
 
 
题目大意: n个军团, 两种操作, 一种是编号为x的军团移动一步, 一个是编号为x的军团这行这列的所有军团都移动到x的位置, 并输出花费. 强制在线.
之前没有用并查集一直tle, 后来想想用并查集时间优化还是相当可观的. 也就是第二个操作将所有移动到x的棋子的根指向x, map的那一行那一列只留x一个, 并用结构(我用的plli)存储这个点集位置和里面有多少军团. 用map来维护每行每列有哪些根, 第一种操作就正常地查找x所在的根(如果只有x一个元素就删除)移动插入; 第二种操先查找x所在的根获得, 之后遍历改行该列, 更新ret值,将所有点指向一个新的根(cnt++), 删掉map<int,set<int> >row,col中已经移走的节点(这里居然开始就没想好.. 遍历行的时候需要随时删掉对应列的点;反之亦然. 最后还要将这一行一列clear) , 然后插入唯一的新的根, 结束操作.
 
虽然是写之前看明白的单写出来还是跟大牛写的顺序一模一样...不看还是不会..http://blog.csdn.net/faithdmc/article/details/38223667
 
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cstring>

using namespace std;

#define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++)
#define fer(i, x, n) for (int i = (int)(x), _n = (int)(n); i < _n; i++)
#define mkp make_pair

#define X first
#define Y second

template<class T> inline void smin(T &a, T b){if(b<a)a=b;}
template<class T> inline void smax(T &a, T b){if(a<b)a=b;}

typedef long long ll;
typedef pair<ll,ll> pll;

const int mod = 1000000007;

////
typedef pair<pll,int> plli;
ll n,lastans,x,y,T,tmp,cnt,m,d;
plli troop[200009];
map<ll,set<int> > col,row;
int ff[200009];
    set<int>::iterator ite;
char c;
int findroot(int x){
    if(ff[x]!=x) ff[x]=findroot(ff[x]);
    return ff[x];
}

void move(){
    int root = findroot(x);
    ll tx=troop[root].X.X,ty=troop[root].X.Y;
    troop[root].Y--;
    if(troop[root].Y==0) row[troop[root].X.X].erase(root),col[troop[root].X.Y].erase(root);
    switch(c){
        case 'U': tx-=d; break;
        case 'D': tx+=d; break;
        case 'L': ty-=d; break;
        case 'R': ty+=d; break;
    }
    ff[x]=x; troop[x]=mkp(mkp(tx,ty),1);
    row[tx].insert(x); col[ty].insert(x);
}
inline ll f(ll x){ return (x>0?(x%mod):((-x)%mod));}
ll query(){
    ll ret=0;
    int root = findroot(x),num = 0;
    ll tx=troop[root].X.X,ty=troop[root].X.Y;
    for(ite = row[tx].begin();ite!=row[tx].end();ite++){
        ret= f(ret+ f(troop[*ite].Y * f(f(troop[*ite].X.Y-ty)*f(troop[*ite].X.Y-ty)))),num+=troop[*ite].Y,ff[*ite]=cnt,col[troop[*ite].X.Y].erase(*ite);
    }
    for(ite = col[ty].begin();ite!=col[ty].end();ite++){
        ret= f(ret+ f(troop[*ite].Y * f(f(troop[*ite].X.X-tx)*f(troop[*ite].X.X-tx)))),num+=troop[*ite].Y,ff[*ite]=cnt,row[troop[*ite].X.X].erase(*ite);
    }
    troop[cnt]=mkp(mkp(tx,ty),num);
    ff[cnt]=cnt;
    row[tx].clear(); col[ty].clear();
    row[tx].insert(cnt); col[ty].insert(cnt);
    cnt++;
    return ret;
}
int main()
{
    //freopen("in.txt","r",stdin);
    ios_base::sync_with_stdio(0);
    while(scanf("%I64d %I64d",&n,&m)!=EOF){
        row.clear(); col.clear(); lastans=0; cnt = n+1;
        fer(i,1,n+1) scanf("%I64d %I64d",&troop[i].X.X,&troop[i].X.Y),ff[i]=i,row[troop[i].X.X].insert(i),col[troop[i].X.Y].insert(i),troop[i].Y=1;
        scanf("%I64d",&T);
        rep(tt,T){
            scanf("\n%c %I64d",&c,&x); x^=lastans;
            if(c!='Q') scanf("%I64d",&d),move();
            else lastans = query(),printf("%I64d\n",lastans);
        }
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/rewrite/p/3946650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值