BZOJ1202 差分約束系統 or 並查集

2021-09-24 05:59:54 字數 3149 閱讀 2923

題意很簡單

真是一道絕世好題啊!

一句話題意

給一段區間的和,問有沒有衝突。

(是不是真的一句話(花雞))

分析

這個題不久隨便搞搞就行了嘛,我判斷一下有沒有衝突就行了啊,這很難嗎?

五分鐘後

這咋寫啊?

算了,我不會這個題。

等等!s到t是v,那不就是sum[t]-sum[s-1]=v嗎?那不就是sum[t]-sum[s-1]<=v , sum[s-1]-sum[v]<=-v嗎?

這不就是差分約束嗎?

那不就做完了嘛!

建完了圖,跑spfa,發現有的點進佇列》=n次,那就說明有環,那就說明t-s=v,s-t=v同時存在,那就說明這個是有衝突的了。

但是我們不知道起點是啥,我們就把沒跑過的點都作為起點來一遍吧qwq。

#include

#define sc(n) scanf("%d",&n)

#define pt(n) printf("%d\n",n)

#define rep(i,a,b) for(int i=a;i<=b;i++)

#define vi vector

#define vl vector

#define pb push_back

#define inf 0x3f3f3f3f

using

namespace std;

const

int maxn =

200;

int n,m;

int inq[maxn]

;int vis[maxn]

;int dis[maxn]

;struct node

;vector g[maxn]

;queue<

int> q;

bool

spfa

(int s)}}

}return

true;}

intmain()

);g[t].pb

();}

for(

int i=

0;i<=n;i++)}

}if(found)

printf

("true\n");

else

printf

("false\n");

}return0;

}

先別急著走鴨。

下面我們來說一說並查集的做法。

並查集的做法理解起來就有一點難了。

首先我們明確乙個事情,如果兩段區間有公共點,我們是不是就可以算出這兩段和合併後的這一段的資訊了。

舉個栗子:

sum[b]-sum[a]=k1

sum[c]-sum[a]=k2

那麼sum[b]-sum[c] = k1-k2

那麼這個東西有什麼用處呢?

如果我們知道了s和t,我們知道了另外乙個點r,那麼我們就可以求出來他們的資訊了。

如果我們把s和t放進並查集裡,r作為他們的父親,那麼,問題是不是有了新的進展了呢?

顯然如果s和t在乙個集合裡面,那麼問題就更容易解決了。(?)

(這裡打了乙個問號,意為大家看到後面就會明白了。)

設s的根節點為rs,t的根節點為rt,i的根節點為ri

設pre[i]表示字首和

設sum[i]=pre[i]-pre[ri]

如果s和t在乙個集合內,則rs=rt

方便起見,令s = s-1

則sum[t]-sum[s]=pre[t]-pre[rt]-pre[s]+pre[rs] = pre[t]-pre[s]。

即若s和t在乙個集合裡面,那麼他們的區間和就是sum[t]-sum[s],(是不是很妙)

然後我們判斷一下這個是否和給出的條件一樣就可以判斷是否衝突了。

若s和t不在乙個集合裡面,我們就需要合併他們,我們現在把t合併到s集合上。

即p[rt] = rs。即rrt = rs。

那麼sum[rt] = pre[rt]-pre[rrt] = pre[rt]-pre[rs]。

而sum[s] = pre[s]-pre[rs], sum[t] = pre[t]-pre[rt]

即pre[rs] = pre[s]-sum[s], pre[rt] = pre[t]-sum[t].

則pre[rt]-pre[rs] = pre[t]-sum[t]-pre[s]+sum[s]。

又因為pre[t]-pre[s] = v.

則sum[rt] = v-sum[t]+sum[s]。

現在合併的時候的權值關係也理清楚了。

那麼這個題目就做完了。

還要注意的一點就是帶全並查集的時候find的過程,一定不能亂掉。

int

find

(int x)

**:

#include

#define sc(n) scanf("%d",&n)

#define pt(n) printf("%d\n",n)

#define rep(i,a,b) for(int i=a;i<=b;i++)

#define vi vector

#define vl vector

#define pb push_back

using

namespace std;

const

int maxn =

1000

;int p[maxn]

,sum[maxn]

;int n,m;

intfind

(int x)

void

unite

(int s,

int t,

int v)

intmain()

scanf

("%d%d"

,&n,

&m);

for(

int i=

0;i)else}if

(found)

printf

("true\n");

else

printf

("false\n");

}return0;

}

狡猾的商人 bzoj1202 差分約束

刁奼接到乙個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為ai i 1,2,3 n 1,n 當 ai大於0時表示這個月盈利ai 元,當 ai小於0時表示這個月虧損ai 元。所謂一段時間內的總收入,就是這段時間內每個月的收入額的總和...

BZOJ 2330 差分約束系統

差分約束系統是用最短路的三角不等式來得到題目中給定的不等式的一組解,具體來說,最短路中的不等式為if dis v dis u len p dis v dis u len p 假設題目中給定不等式a b 5,那麼轉換的不等式即為if dis a dis b 5 dis a dis b 5,這樣就把數學...

BZOJ 2330 差分約束系統

傳送門 差分約束這裡做個簡單介紹 形如 x i x j d 的不等式,可以聯想到我們求最短路時 d v d u len 則上式可以變形為 x i x j d 即連一條j i的長度為d的邊並跑最長路,dis i 則是滿足條件的最小解 因為上面等式採用的 號,所以求出的時最小解,同理當變形為 x j x...