题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=1202

题目大意:

刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。 刁姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。 现在,刁姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。

思路:

一:差分约束系统转化

对于一段区间的和,可以转化成前缀和相减的形式。

比如区间a-b的和为c,也就是sum[b] - sum[a - 1] = c

可以写成两个式子:

sum[b] - sum[a - 1] <= c

sum[b] - sum[a - 1] >= c

根据差分约束系统式子:

也就是a-1到b 权值为c

b到a-1 权值为-c

判断有没有负环,有的话无解,输出false。

二、带权并查集:

也是转化成前缀和的形式。对于每个节点所带的权值cnt[i] = s[root] - s[i]

1、如果x=a-1,y=b在同一子树中,cnt[x] = s[root] - s[x] cnt[y] = s[root] - s[y]

那么cnt[x] - cnt[y] = s[y] - s[x]判断是否等于输入值c。

2、不在同一子树,进行合并。

设fx为x子树根节点 fy为y子树根节点。

有cnt[x] = s[fx] - s[x] cnt[y] = s[fy] = s[y] 目前又给出条件:s[y] - s[x] = z;

将fy并入fx中,那么cnt[fy]应该设置成s[fx] - s[fy]

由上述三个式子可得:cnt[fy]应该设置成cnt[x] - cnt[y] - z

这样带权并查集的合并就写好了。

差分:

 #include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
#define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Mem(a) memset(a, 0, sizeof(a))
#define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
#define MID(l, r) ((l) + ((r) - (l)) / 2)
#define lson ((o)<<1)
#define rson ((o)<<1|1)
#define Accepted 0
#pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} typedef long long ll;
const int maxn = + ;
const int MOD = ;//const引用更快,宏定义也更快
const int INF = 1e9 + ;
const double eps = 1e-; struct edge
{
int v, w;
edge(){}
edge(int v, int w):v(v), w(w){}
};
vector<edge>e;
vector<int>G[maxn];
bool inq[maxn];//是否在队列中
int d[maxn];
int cnt[maxn];//入队次数
int n, m;
void addedge(int u, int v, int w)
{
e.push_back(edge(v, w));
G[u].push_back(e.size() - );
}
bool SPFA()
{
queue<int>q;
memset(inq, , sizeof(inq));
memset(cnt, , sizeof(cnt));
for(int i = ; i <= n; i++){d[i] = ; inq[] = true;q.push(i);}
while(!q.empty())
{
int u = q.front();
q.pop();
inq[u] = ;
for(int i = ; i < G[u].size(); i++)
{
int v = e[G[u][i]].v;
int w = e[G[u][i]].w;
if(d[v] > d[u] + w)
{
d[v] = d[u] + w;
if(!inq[v])
{
q.push(v);
inq[v] = ;
if(++cnt[v] > n)return true;
}
}
}
}
return false;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++)G[i].clear();
e.clear();
int u, v, w;
for(int i = ; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
u--;
addedge(u, v, w);
addedge(v, u, -w);
}
if(SPFA())puts("false");
else puts("true");
}
return Accepted;
}

带权并查集:

 #include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
#define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Mem(a) memset(a, 0, sizeof(a))
#define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
#define MID(l, r) ((l) + ((r) - (l)) / 2)
#define lson ((o)<<1)
#define rson ((o)<<1|1)
#define Accepted 0
#pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} typedef long long ll;
const int maxn = + ;
const int MOD = ;//const引用更快,宏定义也更快
const int INF = 1e9 + ;
const double eps = 1e-; int cnt[maxn];//cnt[i]表示s[root] - s[i]
int p[maxn];
int Find(int x)
{
if(x == p[x])return x;
int tmp = Find(p[x]);//此处不可以先路径压缩,需要更新x之后再进行路径压缩
cnt[x] += cnt[p[x]];//一开始 cnt[x] = s[p[x]] - s[x] cnt[p[x]] = s[root] - s[p[x]]
p[x] = tmp; //需要路径压缩转化成 cnt[x] = s[root] - s[x]
return p[x];
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++)p[i] = i, cnt[i] = ;
int flag = ;
for(int i = ; i <= m; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
x--;
int fx = Find(x), fy = Find(y);
if(fx != fy)
{
//目前已知 s[y] - s[x] = z cnt[x] = s[fx] - s[x] cnt[y] = s[fy] - s[y]
//将y的根fy并入x的根fx中 那么需要设置cnt[fy] = s[fx] - s[fy]
//所以cnt[fy] = s[fx] - s[fy] = s[x] + cnt[x] - (s[y] + cnt[y]) = cnt[x] - cnt[y] - z
cnt[fy] = cnt[x] - cnt[y] - z;
p[fy] = fx;
}
else if(cnt[x] - cnt[y] != z)//验证s[y] - s[x] == z 等价于验证 cnt[x] - cnt[y] == z
{
flag = ;
}
}
if(flag)puts("false");
else puts("true");
}
return Accepted;
}

BZOJ 1202 狡猾的商人 差分约束or带权并查集的更多相关文章

  1. BZOJ 2333 棘手的操作(离线+线段树+带权并查集)

    这题搞了我一天啊...拍不出错原来是因为极限数据就RE了啊,竟然返回WA啊.我的线段树要开8倍才能过啊... 首先可以发现除了那个加边操作,其他的操作有点像线段树啊.如果我们把每次询问的联通块都放在一 ...

  2. BZOJ 3376 [Usaco2004 Open]Cube Stacking 方块游戏(带权并查集)

    题解 #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #in ...

  3. BZOJ 1202: [HNOI2005]狡猾的商人( 差分约束 )

    好像很多人用并查集写的... 前缀和, 则 sumt - sums-1 = v, 拆成2条 : sumt ≤ sums-1 + v, sums-1 ≤ sumt - v 就是一个差分约束, 建图跑SP ...

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

    题意:一个账本记录了N个月以来的收入情况,现在有一个侦探员不同时间偷看到M段时间内的总收入,问这个账本是否为假账. 解法:带权并查集+前缀和.   判断账本真假是通过之前可算到的答案与当前读入的值是否 ...

  5. BZOJ.4500.矩阵(差分约束 SPFA判负环 / 带权并查集)

    BZOJ 差分约束: 我是谁,差分约束是啥,这是哪 太真实了= = 插个广告:这里有差分约束详解. 记\(r_i\)为第\(i\)行整体加了多少的权值,\(c_i\)为第\(i\)列整体加了多少权值, ...

  6. Bzoj1202/洛谷P2294 [HNOI2005]狡猾的商人(带权并查集/差分约束系统)

    题面 Bzoj 洛谷 题解 考虑带权并查集,设\(f[i]\)表示\(i\)的父亲(\(\forall f[i]<i\)),\(sum[i]\)表示\(\sum\limits_{j=fa[i]} ...

  7. luogu 2294 狡猾的商人 带权并查集

    此题做法多啊 带权并查集,区间dp,前缀和,差分约束 1.自己写的前缀和, 11 #include<bits/stdc++.h> #define rep(i,x,y) for(regist ...

  8. 【bzoj1202】[HNOI2005]狡猾的商人 带权并查集

    题目描述 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表 ...

  9. luogu 2294 [HNOI2005]狡猾的商人 差分约束

    一个差分约束模型,只需判一下有没有负环即可. #include <bits/stdc++.h> #define N 103 #define M 2004 #define setIO(s) ...

随机推荐

  1. 微信小程序自学过程中遇到的问题 转

    view标签下hover必须为true时,设置hover-class才有效,hover-start-time和hover-stay-time的形式如下:   < view class=" ...

  2. WCF-终结点之消息路由示例

    一. 在前一章中主要介绍了服务端的监听地址与逻辑地址.本节模拟消息转发机制来实际体验一把终结点的监听地址是如何使用的. 先下载一个叫做TcpTrace的小软件(108k),它能够截取端口消息,并转发消 ...

  3. js原型及原型链解析

    js原型.原型链 这几天闲了看了下js的原型,以下内容为个人理解,如有错误,尽请指正. 首先,明确一点:js中的对象分为普通对象和函数对象,一般我们自定义的可以被new的函数称作函数对象,另外js内置 ...

  4. 关于C# 委托(delegate)与事件(event)的用法及事例

    C#中的委托和事件对于新手可能会有一点难理解,所以先从一个小例子入手,以便能更好的理解其如何使用.有一个学生每天定闹钟在早上6点起床,所以当每天早上6点的时候,闹钟就会响起来,从而学生才会按时起床. ...

  5. vmware创建centos虚拟机

    下载centos 安装之前你需要下载centos镜像:http://mirrors.aliyun.com/ 创建虚拟机 如果还没有安装vmware请参考:https://www.cnblogs.com ...

  6. MySQL数据源驱动报错

    报错信息:MySQL数据源驱动报错: 1.mysql8.0以上版本需要连接数据库的JDBC驱动也是8.0版本以上 com.mysql.cj.jdbc.Driver 2.MySQL高版本需要指明是否需要 ...

  7. UML 简介笔记

    1. UML 是什么? UML 统一建模语言是一组图形表示法,可以帮助描述和设计软件系统,特别是使用面向对象 OO 风格建造的软件系统. 2. 使用 UML 的方式 UML 有 3 种使用模式:草稿, ...

  8. MySQL数据导出为Excel, json,sql等格式

    MySQL数据经常要导出为Excel, json,sql等格式,通过步骤都很多,麻烦,现在通过Treesoft可以方便的导出你要的数据格式. 1.在线执行SQL,在数据列表中有相应按钮,方便的将数据导 ...

  9. 已注册成Portal联合服务器的Server,如何修改机器名?

    1.产品版本 ArcGIS for Server 10.2.2 2.修改说明 本环境中,Portal for ArcGIS和ArcGIS for Server两个产品安装在同一台机器上.安装前已将完全 ...

  10. Android SD卡上文件

    1. 得到存储设备的目录:/SDCARD(一般情况下) SDPATH=Environment.getExternalStorageDirectory()+"/"; 2. 判断SD卡 ...