[BZOJ1202][HNOI2005]狡猾的商人(并查集+前缀和)

题目描述

传送门

题解

刚开始感觉只有几个区间和另外几个区间都拼成了同一个区间的时候才有可能判false,然后xjblg写出了一个对拍都不过的code然后交上去A了= =可见数据之弱。

网上的正解是并查集,YY了挺久的。

读入区间(l,r,w),如果l和r不在一个集合里,将它们合并;否则判断dis_r-dis_x是否等于w(其中dis_i表示i到它祖先的距离)

代码

xjblg

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=105;
const int max_m=1005;

int T,n,m;
bool flag,vis[max_n][max_n];
int f[max_n][max_n];
struct hp{int x,y,w;}edge[max_m];

inline void clear()
{
    memset(vis,0,sizeof(vis));
    memset(f,0,sizeof(f));
}
inline int cmp(hp a,hp b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        clear();
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;++i)
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].w);
        sort(edge+1,edge+m+1,cmp);
        flag=true;
        for (int i=1;i<=m;++i)
        {
            if (!vis[edge[i].x][edge[i].y])
            {
                vis[edge[i].x][edge[i].y]=true;
                f[edge[i].x][edge[i].y]=edge[i].w;
            }
            else
                if (f[edge[i].x][edge[i].y]!=edge[i].w)
                {
                    flag=false;
                    break;
                }
            for (int j=edge[i].x-1;j>=1;--j)
            {
                if (vis[j][edge[i].x-1])
                {
                    if (!vis[j][edge[i].y])
                    {
                        vis[j][edge[i].y]=true;
                        f[j][edge[i].y]=f[j][edge[i].x-1]+f[edge[i].x][edge[i].y];
                    }
                    else
                        if (f[j][edge[i].y]!=f[j][edge[i].x-1]+f[edge[i].x][edge[i].y])
                        {
                            flag=false;
                            break;
                        }
                }
            }
            if (!flag) break;
        }
        if (flag) printf("true\n");
        else printf("false\n");
    }
}

并查集+前缀和

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=105;

int T,n,m,l,r,w,fl,fr;
bool flag;
int f[max_n],dis[max_n];

inline int find(int x)
{
    if (x!=f[x])
    {
        int t=find(f[x]);
        dis[x]+=dis[f[x]];
        f[x]=t;
    }
    return f[x];
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        for (int i=0;i<=n;++i) f[i]=i,dis[i]=0;
        flag=true;
        for (int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&l,&r,&w);
            l--;
            fl=find(l); fr=find(r);
            if (fl!=fr)
            {
                dis[fr]=dis[l]-dis[r]+w;
                f[fr]=fl;
            }
            else
                if (dis[r]-dis[l]!=w)
                    flag=false;
        }
        if (flag) printf("true\n");
        else printf("false\n");
    }
}
时间: 2024-10-10 18:46:20

[BZOJ1202][HNOI2005]狡猾的商人(并查集+前缀和)的相关文章

bzoj1202: [HNOI2005]狡猾的商人(并查集 差分约束)

1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4127  Solved: 1981[Submit][Status][Discuss] Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai

BZOJ1202 [HNOI2005]狡猾的商人 并查集维护前缀和

1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1935  Solved: 936[Submit][Status][Discuss] Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元

bzoj 1202: [HNOI2005]狡猾的商人 并查集好题

1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2946  Solved: 1384[Submit][Status][Discuss] Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai

BZOJ 1202 HNOI2005 狡猾的商人 并查集

题目大意:给定一个序列,m次给出一段区间的和,求这个序列是否合法 第一眼看还以为是差分约束- - [x,y]区间内和为z等价于sum[y]-sum[x-1]=z 用并查集来维护这个关系即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 110 using namespace std; int n,m; int fa[M],f[M]

bzoj1202: [HNOI2005]狡猾的商人(差分约束)

1202: [HNOI2005]狡猾的商人 题目:传送门 题解: 据说是带权并查集!蒟蒻不会啊!!! 可是听说lxj大佬用差分约束A了,于是开始一通乱搞. 设s[i]为前i个月的总收益,那么很容易就可以推出约束条件了啊:  s[x-1]>=s[y]-c s[y]>=s[x-1]+c 然后就可以去跑最长路了 吐槽: lxj大佬推出来的条件竟然是两个小于等于号:s[x-1]<=s[y]-c s[y]<=s[x-1]+c 然后跑最短路也A了,表示很玄学qwq 代码: 1 #include

【BZOJ1202】【HNOI2005】狡猾的商人 并查集

题解:呃,这个题太耿直了. 还能有负收益,也就是一个区间只需要有某段时间没有确定,或者有重叠,那就"一切皆有可能". 只有边界完全重合的一些区间神马的才能判错. 于是写个耿直的并查集就好了.(可以a~b收益为c,a>b,反正有负收益233) 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 105 u

bzoj1202 [HNOI2005]狡猾的商人

题目链接 并查集 听说有人用差分约束做,我哪天也去试一试 并查集维护后缀和,从前往后合并 注意路径压缩的时候要修改后缀和 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<

bzoj 1202: [HNOI2005]狡猾的商人(并查集+前缀和)

1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2573  Solved: 1209 [Submit][Status][Discuss] Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损A

【bzoj 1202】[HNOI2005] 狡猾的商人(图论--带权并查集+前缀和)

题意:一个账本记录了N个月以来的收入情况,现在有一个侦探员不同时间偷看到M段时间内的总收入,问这个账本是否为假账. 解法:带权并查集+前缀和.   判断账本真假是通过之前可算到的答案与当前读入的值是否相同来完成.那么就是只有知道新读入的区间2端的(在相同区域内的!!)前缀和才可以判断,也就是这2个端点之前被纳入了相同的区域内才可以判断.于是,我们就可以想到并查集了.(( ′? ??`) 真的么......)   假设已知x~y月的总收入为d,那么s[y]-s[x-1]=d.一般前缀和是算上自己的