HDU-4879-ZCC loves march(map+set+并查集)

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 

思路:分别用map来维护与x坐标平行和垂直的线上面的集合,集合里面直接存对应元素的下标,并用并查集维护,根节点可以用来表示所在的集合。当移动一个元素时,先找到该元素下标对应的根,根对应的num-1,并把移动的元素插到新的位置上,他的根就是他自己。执行Q操作时,通过map找到同一行和同一列的所有集合进行计算,再把这些计算过的集合删掉,同时下标指向新的根(即移动之后形成的新的集合)。

#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
using namespace std;

struct TROOP{
LL x,y,num;
TROOP(){}
TROOP(LL nx,LL ny,LL nnum){x=nx,y=ny,num=nnum;}
}troop[200005];

map<LL,set<LL> >MX;
map<LL,set<LL> >MY;
set<LL>::iterator it;

LL node[200005];

LL findroot(LL x)
{
    if(node[x]!=x) node[x]=findroot(node[x]);

    return node[x];
}

int main()
{
    LL m,x,y,n,i,t,cnt,root,a,b,ans;
    char s[5];

    while(~scanf("%I64d%I64d",&n,&m))
    {
        MX.clear();
        MY.clear();

        for(i=1;i<=n;i++)
        {
            scanf("%I64d%I64d",&x,&y);

            troop[i].x=x;
            troop[i].y=y;
            troop[i].num=1;

            node[i]=i;

            MX[x].insert(i);
            MY[y].insert(i);
        }

        cnt=n+1;

        ans=0;

        scanf("%I64d",&t);

        while(t--)
        {
            scanf("%s",s);

            if(s[0]=='Q')
            {
                scanf("%I64d",&a);

                a^=ans;

                root=findroot(a);//找到a所在的集合

                x=troop[root].x;
                y=troop[root].y;

                LL num=0;

                ans=0;

                for(it=MX[x].begin();it!=MX[x].end();it++)
                {
                    num+=troop[*it].num;

                    LL temp=abs(troop[*it].y-y);

                    temp%=mod;

                    ans=(temp*temp%mod*troop[*it].num%mod+ans)%mod;

                    node[*it]=cnt;//指向cnt,cnt是执行Q操作之后新的根,用来标记新的集合

                    MY[troop[*it].y].erase(*it);//*it已经计算过,从MY[]集合里删掉,避免重复计算
                }

                for(it=MY[y].begin();it!=MY[y].end();it++)
                {
                    num+=troop[*it].num;

                    LL temp=abs(troop[*it].x-x);

                    temp%=mod;

                    ans=(temp*temp%mod*troop[*it].num%mod+ans)%mod;

                    node[*it]=cnt;//同理

                    MX[troop[*it].x].erase(*it);//同理
                }

                node[cnt]=cnt;//指向自己,别忘了
                troop[cnt]=TROOP(x,y,num);//执行Q操作之后形成的新集合
                MX[x].clear();
                MY[y].clear();
                MX[x].insert(cnt);//在目标集合中插入
                MY[y].insert(cnt);

                cnt++;

                printf("%I64d\n",ans);
            }
            else
            {
                scanf("%I64d%I64d",&a,&b);

                a^=ans;

                root=findroot(a);//找到a所在的集合,即a的根节点

                x=troop[root].x;
                y=troop[root].y;

                troop[root].num--;//集合里的计数减一

                if(!troop[root].num)//如果集合的计数为0则把该集合删掉
                {
                    MX[x].erase(root);
                    MY[y].erase(root);
                }

                if(s[0]=='U')
                {
                    troop[a]=TROOP(x-b,y,1);

                    node[a]=a;//a指向自己,作为新的根

                    MX[x-b].insert(a);//在目标位置插入
                    MY[y].insert(a);
                }
                else if(s[0]=='L')//以下同理
                {
                    troop[a]=TROOP(x,y-b,1);

                    node[a]=a;

                    MX[x].insert(a);
                    MY[y-b].insert(a);
                }
                else if(s[0]=='D')
                {
                    troop[a]=TROOP(x+b,y,1);

                    node[a]=a;

                    MX[x+b].insert(a);
                    MY[y].insert(a);
                }
                else if(s[0]=='R')
                {
                    troop[a]=TROOP(x,y+b,1);

                    node[a]=a;

                    MX[x].insert(a);
                    MY[y+b].insert(a);
                }
            }
        }
    }
}

HDU-4879-ZCC loves march(map+set+并查集)

时间: 2024-12-20 14:15:45

HDU-4879-ZCC loves march(map+set+并查集)的相关文章

HDU 4879 ZCC loves march(并查集+set)

题意:一个最大10^18*10^18的矩阵,给你最多十万个士兵的位置,分别分布在矩阵里,可能会位置重复,然后有2种操作,一种是把第i个士兵向上下左右移动,另一种是把第i个士兵与他横坐标纵坐标相同的士兵全部移到这个点上,然后要计算花费. 这道题我想了好几天.在看了标程得到一些提示后总算写出来了.加了读入优化后快了100ms左右达到546ms. 做法:开2个set分别维护X相同的和Y相同的,但是会有相同位置点的坐标,该怎么办?用并查集去维护相同位置的点,读入的时候就可能会有位置相同的点,所以读的时候

HDU 4879 ZCC loves march (并查集,set,map)

题面以及思路:https://blog.csdn.net/glqac/article/details/38402101 代码: #include <bits/stdc++.h> #define LL long long using namespace std; const LL mod = 1000000007; const int maxn = 2000010; struct node { LL x, y; int cnt; node(){} node(LL x, LL y, int cnt

HDU 4879 ZCC loves march (2014多校2-1008,数据结构,STL,模拟题)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4879 题意: 给一个n*m的矩阵,有n个人,t次操作,操作有以下两种: 1.令编号x的人上下左右移动 2.令与编号x的人同行同列的人聚集到x这里,输出花费 方法: 使用两个set,一个维护x轴,一个维护y轴 一个map<point,int>,表示这一个point有多少个人 然后根据要求的操作直接操作即可,nlgn复杂度 注意: 1.由于set或者map是红黑树,所以删除节点的后,内部节点重排,it+

hdu 4882 ZCC Loves Codefires(数学题+贪心)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4882 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593830943

HDU 4876 ZCC loves cards

我决定记录下这么恶心的代码.比赛的时候头晕脑胀,写得好搓,错的地方好多好多,回来调了好久.... 做法大概就是C(20,6)选出卡牌后,再k!枚举排列,再k*k得出该排列能得出什么数字. 当然,光这样做绝对会T,里面加了各种剪枝后就1650ms险过了.. 最主要的剪枝是选出k张牌后,看牌能不能组成L~ans里面各个数字,能才进行下一步.然后k!可以拆成(k-x)!*(x!)..不过这里其实大概没什么大优化吧 #include<cstdio> #include<iostream> #

hdu 4876 ZCC loves cards(暴力)

题目链接:hdu 4876 ZCC loves cards 题目大意:给出n,k,l,表示有n张牌,每张牌有值.选取其中k张排列成圈,然后在该圈上进行游戏,每次选取m(1≤m≤k)张连续的牌,取牌上值的亦或和.要求找到一个圈,使得L~R之间的数都可以得到,输出R.如果R < L输出0. 解题思路:暴力,首先预处理出来每种选取的亦或值,然后在该基础上从可以组成L的状态中挑选一个,L+1的状态中挑取一个,知道说总的挑取出所有状态中选中的牌的个数大于K为值,然后用全排序去查找最大的R. #includ

hdu 5229 ZCC loves strings

题意: CC有N个字符串,他正在和Miss G.用这N个字符串玩一个小游戏.ZCC会从这N个串中等概率随机选两个字符串(不可以是同一个).然后,ZCC和Miss G.轮流操作.Miss G.总是先操作的.在每轮中,操作者可以选择操作A或操作B. 操作A:在两个串中选择一个当前非空的串,然后在这个串的末尾删去一个字符. 操作B: 若当前两个串完全相同且非空,则可以使用这个操作.此时两个串都被清空. 不能操作的玩家输掉了这个游戏. ZCC想要知道他输掉游戏的概率是多少(也就是Miss G.获胜的概率

HDU 4873 ZCC Loves Intersection(JAVA、大数、推公式)

在一个D维空间,只有整点,点的每个维度的值是0~n-1 .现每秒生成D条线段,第i条线段与第i维度的轴平行.问D条线段的相交期望. 生成线段[a1,a2]的方法(假设该线段为第i条,即与第i维度的轴平行)为,i!=j时,a1[j]=a2[j],且随机取区间[0,n-1]内的整数.然后a1[i],a2[i]在保证a1[i]<a2[i]的前提下同样随机. 由于D条线段各自跟自己维度的轴平行,我们可以转换成只求第i个维度与第j个维度的相交期望,然后乘以C(2,n)就好了 显然线段[a1,a2]和线段[

HDU 4876 ZCC loves cards _(:зゝ∠)_ 随机输出保平安

GG,,,g艹 #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <vector> #include <queue> #include <math.h> using namespace std; vector<int>G[21][7];//G[i][j] 表示n=i k=j的情况下 二进