HDOJ3047 Zjnu Stadium --- 带权并查集

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3047

Problem Description

In 12th Zhejiang College Students Games 2007, there was a new stadium built in Zhejiang Normal University. It was a modern stadium which could hold thousands of people. The audience Seats made a circle. The total number of columns were 300 numbered 1--300, counted clockwise, we assume the number of rows were infinite.
These days, Busoniya want to hold a large-scale theatrical performance in this stadium. There will be N people go there numbered 1--N. Busoniya has Reserved several seats. To make it funny, he makes M requests for these seats: A B X, which means people numbered B must seat clockwise X distance from people numbered A. For example: A is in column 4th and X is 2, then B must in column 6th (6=4+2).
Now your task is to judge weather the request is correct or not. The rule of your judgement is easy: when a new request has conflicts against the foregoing ones then we define it as incorrect, otherwise it is correct. Please find out all the incorrect requests and count them as R.

 

 

Input

There are many test cases:
For every case: 
The first line has two integer N(1<=N<=50,000), M(0<=M<=100,000),separated by a space.
Then M lines follow, each line has 3 integer A(1<=A<=N), B(1<=B<=N), X(0<=X<300) (A!=B), separated by a space.
 

 

 

Output

For every case: 
Output R, represents the number of incorrect request.

 

 

Sample Input

 

10 10 1 2 150 3 4 200 1 5 270 2 6 200 6 5 80 4 7 150 8 9 100 4 8 50 1 7 100 9 2 100

 

 

Sample Output

 

2

Hint

Hint: (PS: the 5th and 10th requests are incorrect)

题意: 体育场有环形座位共300列,每列有无数行。

每个人有张票,上面有座位信息。

观众编号1....N

为了让游戏有趣,座位信息表示为x,y,w, 即编号为y的观众必须坐在x观众右边距离为w列处,

比如说, 座位信息为1,3,5,1号观众座位列数为10,则3号观众必须坐在第15列。

每个观众依次入场,检查座位信息,如果座位信息与前面的已知信息矛盾,则认定为假票。

给定m个座位信息,判断有多少张假票。

题解:这是典型的带权并查集。 如下图所示,y->x表示y在x右边距离w列处。

所以y在x右边w列处,y'在x右边w'处,利用向量计算,则y在y'右边w-w'列处。(可能没表达清楚,看图就懂了)

所以每次输入座位信息时,判断两个点的公共祖先是否相同,相同的话利用下图的向量计算两点的w(采用路径压缩并查集确保两个有公共祖先的节点距离祖先距离最多为1),然后比较输入的w,如果不等就是假票。如果公共祖先不同,就合并节点,合并的时候记得再用向量计算更新权值。

最后注意下更新权值时为避免权值为负,结果可以加上300再模上300,这样结果如果为正,就相当于加0没硬性,结果为负就把它校正为正值。

 

#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAXN 50010
using namespace std;
int const MOD = 300;
int n,m;
int pre[MAXN]; // 父亲节点
int weight[MAXN];  // 边权

// 查找祖先节点(路径压缩)
int Find(int x) {
    if(pre[x] == x) {
        return x;
    }
    int father = Find(pre[x]);
    weight[x] = (weight[x] + weight[pre[x]]) % MOD; 
    pre[x] = father;// 路径压缩 
    return father;    
}

// 合并节点,返回值:是否是真票(y->x权值为w)
bool Union(int x,int y,int w) {
    int xx = Find(x);
    int yy = Find(y);
    if(xx == yy) {
        int t = (weight[y] - weight[x] + MOD) % MOD;// y到x的权值
        return t == w;
    }
    // 没有公共祖先
    pre[yy] = xx;
    //weight[yy] + weight[y] - weight[x] = w;
    weight[yy] = (weight[x] - weight[y] + w + MOD) % MOD; // 更新权值
    return true;
}

// 初始化
void Init() {
    for(int i = 1;i <= n;i++) {
        pre[i] = i;
    }
    memset(weight,0,sizeof(weight));
}
int main()
{
    while(scanf("%d%d",&n,&m) != EOF) {
    	Init();
        int x,y,w;
        bool result;
        int cnt = 0;
        for(int i = 0;i < m;i++) {
            scanf("%d%d%d",&x,&y,&w);
            result = Union(x,y,w);
            if(!result) cnt++; //假票
        }
        printf("%d\n",cnt);
    }
    
    return 0;
} 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值