题目链接:

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. ListView和BaseAdapter

    参考资料:http://www.runoob.com/w3cnote/android-tutorial-listview.html <LinearLayout xmlns:android=&qu ...

  2. 欢迎来到GIS思考者的博客www.gisthinker.com

    我是一名GIS爱好者,这是我的个人博客,欢迎点击: GIS思考者:www.gisthinker.com

  3. c# 中 event 和 delegate 的区别

    event 是一种特殊的delegate. 1)event 在本类(派生类也不行)之外不能触发.(如果是public的在类外或protected的在派生类中可以使用 += 或 -=, 但不能调用该ev ...

  4. Html-完整表格

    表头th 特殊的单元格:加粗.居中 它的用户是取代td的位置即可 <table border="2"> <tr> <th>姓名</th&g ...

  5. Details.cshtml(118): error CS1001: 应输入标识符

    写了没定义 @Html.DisplayFor(model => model.)

  6. java中的奇葩 “:”

    一.经常使用java的人有没有发现java也可以将汉字作为标识符出现呢? 在Java语言中,标识符是以字母.下划线(_)或美元符($)开头,由字母.数字.下划线(_)或美元符($)组成的字符串 真的输 ...

  7. Oracle数据库的监控及数据维护

    目前Oracle数据库的管理,数据查询等都需要安装Oracle软件或安装Oracle Client等,远程访问都需要先登录到服务器等繁琐的操作.如果是开发团队,那么每个开发,测试,管理人员都要经历这个 ...

  8. OpenStack IceHouse 部署 - 1 - 架构说明

    参考架构 Architecture from OpenStack Install Guide Reference Architecture Network Isolation 在本次部署中,我们采用了 ...

  9. 理解域名插槽:slot-scope

    作用域插槽 | 带数据的插槽 最后,就是我们的作用域插槽.这个稍微难理解一点.官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽.什么意思呢,就是前面两种,都是在组件的templa ...

  10. js中的正则表达式的运用

    正则表达式是一个拆分字符串并查询相关信息的过程:是现代开发中很重要的一环.作为一个web开发人员必须牢牢掌握这项技能,才能尽情得在js中驰骋. 1.创建正则表达式: 正则表达式(regular exp ...