zoukankan      html  css  js  c++  java
  • BZOJ 1202 [HNOI2005]狡猾的商人:并查集(维护距离)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1202

    题意:

      有一个账本,记录了n个月的盈亏。

      每个月的数值:正为盈,负为亏。

      你知道m个这个账本的区间和[x[i],y[i]]。

      问你这个账本是真是假。

    题解:

      如果已知区间和[a,b],[b,c],那么就可以算出区间和[a,c]。

      而唯一判断账本真假的方法,就是看有没有某个给定的区间和A[a,c]与推出来的区间和B[a,c]不相等。如果不相等,账本为假。

      我们常用前缀和来处理区间和。

      但此题仅给出点与点之间的差值,因此要用并查集维护:

        某一连通块内各节点到根节点的差值dis[i]。

        如果两点a,b在同一连通块内,则区间和为dis[b] - dis[a-1]。

      根节点dis = 0.

      每次要用到某个dis[x]时,要在之前执行一遍find(x),以更新x的真正父亲,也顺便将dis[x]改为了它与真父亲的差值。

      让px认py作爹时,要更新dis[px] = px到py的差值 = dis[y]-w-dis[x].

      特别要注意前缀和方向:

        “从根到节点的前缀和方向”与“认爹箭头方向”相反。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 105
     5 
     6 using namespace std;
     7 
     8 int n,m,t;
     9 int dis[MAX_N];
    10 int par[MAX_N];
    11 bool flag;
    12 
    13 void init_union_find()
    14 {
    15     memset(dis,0,sizeof(dis));
    16     for(int i=0;i<=n;i++)
    17     {
    18         par[i]=i;
    19     }
    20 }
    21 
    22 int find(int x)
    23 {
    24     if(par[x]==x) return x;
    25     int t=find(par[x]);
    26     dis[x]+=dis[par[x]];
    27     return par[x]=t;
    28 }
    29 
    30 void unite(int x,int y,int w)
    31 {
    32     int px=find(x);
    33     int py=find(y);
    34     if(px==py) return;
    35     dis[px]=dis[y]-w-dis[x];
    36     par[px]=py;
    37 }
    38 
    39 bool same(int x,int y)
    40 {
    41     return find(x)==find(y);
    42 }
    43 
    44 void work()
    45 {
    46     cin>>n>>m;
    47     int x,y,w;
    48     flag=true;
    49     init_union_find();
    50     for(int i=0;i<m;i++)
    51     {
    52         cin>>x>>y>>w;
    53         if(same(x-1,y))
    54         {
    55             if(dis[y]-dis[x-1]!=w)
    56             {
    57                 flag=false;
    58                 return;
    59             }
    60         }
    61         else unite(x-1,y,w);
    62     }
    63 }
    64 
    65 void print()
    66 {
    67     if(flag) cout<<"true"<<endl;
    68     else cout<<"false"<<endl;
    69 }
    70 
    71 int main()
    72 {
    73     cin>>t;
    74     while(t--)
    75     {
    76         work();
    77         print();
    78     }
    79 }
  • 相关阅读:
    使Eclipse下支持编写HTML/JS/CSS/JSP页面的自动提示
    SpringMVC与Struts2的对比
    事务不提交,也有可能写redo和数据文件
    14.4.1 InnoDB Startup Configuration
    SLB 权重问题
    perl 访问网站一些useragent的设置
    14.3.5.3 How to Minimize and Handle Deadlocks 如何减少和处理死锁
    nginx 区分pc和mobile 到不同的404页面
    dokcer 运行和进入容器
    docker 私有仓库查询
  • 原文地址:https://www.cnblogs.com/Leohh/p/7513070.html
Copyright © 2011-2022 走看看