zoukankan      html  css  js  c++  java
  • HDU_3038 How Many Answers Are Wrong 【带权并查集】

    一、题面

    HDU3038

    二、分析

    用并查集可以方便的判断两个位置是否有关系,这种关系可以通过是否有公共父节点判断,如果有公共父节点则可以直接判断是否正确,如果没有公共父节点,就可以把这个条件与之前的联系起来。同时需要设定sum,表示当前点到父节点的权值,这个权值方便后面的判断,这里有几种情况。

    假设输入为$(x,y,w)$,那么对应父节点$fx = find(x), fy = find(y)$:

    1.如果$fx==fy$:那么可以直接判断$w == sum[x] - sum[y]$.

    2.如果$ x < y < fx < fy$:这里需要更新并查集的信息,$par[fx] = fy, sum[fx] = sum[y] - (sum[x] - w)$.

    3.如果$ x < fx < y < fy$:此时,$par[fx] = fy, sum[fx] = sum[y] + (w - sum[x])$.

    4.如果$ x < y < fy < fx$:此时,$par[fy] = fx, sum[fy] = sum[x] - sum[y] - w$.

    分析上面四种情况,可以得出2和3可以合并,对于4,仔细分析一下, 相当于就是3的情况,只是因为$par[fy] = fx$,只是这样可以保证$sum$的值为正。注意在路径压缩时,对$sum$进行更新就可以了。

    细心的朋友可能发现了,还有$x = y$的情况呢。对于这种情况,我们可以直接对输入的左值整体再往左移一下,就是输入的$u$变成$u-1$,这个对结果是没有影响的。但是如果不减,我们就要考虑$x=y$的情况了,前面我们已经初始化了$sum$初值为0,并且$x=y$的左右两边的情况我们是不能保证完全清楚的。所以这样把$x=y$变成了$(x-1,y]$这个区间的形式,就让问题又归到了我们上面讨论的情况,更简单了。

    三、AC代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <fstream>
     5 #include <map>
     6 
     7 using namespace std;
     8 
     9 const int MAXN = 2e5+3;
    10 int par[MAXN];
    11 int sum[MAXN];
    12 
    13 void Init()
    14 {
    15     for(int i = 0; i < MAXN; i++)
    16         par[i] = i;
    17     memset(sum, 0, sizeof(sum));
    18 }
    19 
    20 int Find(int x)
    21 {
    22     if(par[x] == x)
    23         return x;
    24     int fx = par[x];
    25     par[x] = Find(fx);
    26     sum[x] = sum[fx] + sum[x];
    27     return par[x];
    28 }
    29 
    30 bool Union(int x, int y, int w)
    31 {
    32     int fx = Find(x);
    33     int fy = Find(y);
    34     // if(fx != fy)
    35     // {
    36     //     par[fx] = fy;
    37     //     sum[fx] = w + sum[y] - sum[x];
    38     //     return true;
    39     // }
    40     // else
    41     // {
    42     //     return w == sum[x] - sum[y];
    43     // }
    44     if(fx < fy)
    45     {
    46         par[fx] = fy;
    47         sum[fx] = w + sum[y] - sum[x];
    48         return true;
    49     }
    50     else if(fx > fy)
    51     {
    52         par[fy] = fx;
    53         sum[fy] = sum[x] - w - sum[y];
    54         return true;
    55     }
    56     else
    57     {
    58         return w == sum[x] - sum[y];
    59     }
    60 
    61 }
    62 
    63 int main()
    64 {
    65    // freopen("input.txt", "r", stdin);
    66     int N, M;
    67     while(scanf("%d %d", &N, &M)!=EOF)
    68     {
    69         Init();
    70         int a, b, w, ans = 0;
    71         for(int i = 0; i < M; i++)
    72         {
    73             scanf("%d %d %d", &a, &b, &w);
    74             if(!Union(a-1, b, w))
    75                 ans++;
    76         }
    77         printf("%d
    ", ans);
    78     }
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    Android消息机制解析
    ViewGroup事件分发机制解析
    Android Ptrace Inject
    Android GOT Hook
    Android Exception Hook
    Android Inline Hook
    esp8266 SDK开发之编译流程
    XML文件解析数据结构
    esp8266 SDK开发之GPIO中断
    esp8266 SDK开发之环境搭建
  • 原文地址:https://www.cnblogs.com/dybala21/p/10138765.html
Copyright © 2011-2022 走看看