【ur #2】跳蚤公路
參照yjc方法。也就是地鐵環線那個題。
求每個點不在負環內的x的取值範圍。然後所有1到j能到i的j的範圍取交。得到答案。
每個邊形如kx+b的直線,每個環也是
每個點不在負環內的x取值範圍是區間,
兩次二分,
第一次二分區間左端點,第二次右端點。
如果沒有負環,左端點往左偏,右端點往右偏
否則,記錄負環的構成:k*mid+b的k的正負,可以得到mid應該往**偏。
注意spfa找負環:
記錄has[x]表示到x的最短路已經經過了多少個點,
dis[x]最短路,fr[x]是最短路的前驅,pre[x]是最短路前驅指向x的邊
發現has[x]>n的時候,證明出現了負環。但是x不一定在負環上!
不斷跳fr[x]找到整個環重複的第乙個點z。
再fr[z]找到整個環。
emmm,乙個問題是,負環上的點不會被其他點鬆弛導致fr[*]找不到負環嗎?
由於spfa的bfs性質,以及has[x]>n才會判斷出有負環,
所以整個負環上的點,在判斷has[*]>n之前,要麼不會被鬆弛、或者鬆弛後要麼找到新的負環、要麼會被這個負環再次鬆弛,
總之這個環確實能找出來。
**:目前(2019.6.17)uoj最優解
#include#define reg register int普通二分+判負環#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout
namespace
std;
typedef
long
long
ll;template
il void rd(t &x)
template
il void output(t x)
template
il void ot(t x)
template
il void prt(t a,int st,int nd)
namespace
modulo
il int sub(int x,int y)
il int mul(int x,int y)
il void inc(int &x,int y)
il void inc2(int &x,int y)
il int qm(int x,int y=mod-2)return
ret;}
template
il int ad(const
int a,const
int b,const args &...args)
template
il int mul(const
int a,const
int b,const args &...args) }//
using namespace modulo;
namespace
miracleb[m];
struct
node
}e[2*m];
inthd[n],cnt;
void add(int x,int y,int k,int
b)int
c[n],df,dfn[n],low[n];
intscc;
intf[n][n];
int sta[n],top,in
[n];
intsz[n];
void tarjan(int
x)else
if(in[y]) low[x]=min(low[x],dfn[y]);
}if(low[x]==dfn[x])
while(z!=x);
}}struct
seg seg(ll le,ll ri)
bool
empty()
bool
full()
seg friend
operator &(seg a,seg b)
seg friend
operator |(seg a,seg b)
}lim[n];
ll dis[n];
intpre[n];
intfr[n];
inthas[n];
queue
q;bool
vis[n];
int spfa(int s,ll mid,int
n)while(!vis[z]);
int lp=z;
dowhile(z!=lp);
if(k<0
)else
}if(!vis[y])}}
}return0;
}void calc(int s,int
id)else
if(lp==1
)else
}//cout<
; l=-inf,r=inf;
while(l<=r)
else
if(lp==1
)else
}//cout<
}int
main()
for(reg i=1;i<=n;++i)
}//cout<
}if(s) calc(s,i);
}for(reg i=1;i<=scc;++i) f[i][i]=1
;
for(reg i=1;i<=m;++i)
for(reg k=1;k<=scc;++k)}}
for(reg i=1;i<=n;++i)
}if(ans.empty())
else
if(ans.l==-inf||ans.r==inf)
else
}return0;
}
}signed main()
/*author: *miracle*
*/
因為整個值域都有單調性。知道不合法往**走。
區間二分?+找負環
二分左端點,二分右端點。
麻煩的是,第一次不合法,該往**走?(顯然之後不合法其實是知道往**走的)
因為並沒有單調性。
本題提供的思路是,考慮不合法的構成,來限制往**走才可能合法。
也就是額外記錄一些東西
(好像這個套路暫時只出現於k*mid+b的k正負判斷?)
upda:2019.6.21
官方題解:
利用bellman-ford的思想進行判斷負環。
簡介bellman-ford的方法:
不斷列舉邊數,用所有的邊更新點的dis。
設f[i][j]走了i條邊,到達j點,
最短路如果存在負環,則一定存在乙個負環上的點u,使得f[u][n]
擴充套件一下
f[i][j][k]表示,走了i條邊,到達j點,斜率是k的最小的b值。
找到每個點不在負環的x的取值範圍。
min(f[u][n][k1]+k1*x)>=min(f[u][n-1][k2]+k2*x)的x的個數。
列舉每個k1,求f[u][n][k1]+k1*x>=min(f[u][n-1][k2]+k2*x)
的x區間,再求並。
轉化為:求f[u][n][k1]+k1*x
再列舉k2,解出的所有不等式f[u][n][k1]+k1*x
由於最後答案補集一定是[-inf,l],[l,r],[r,inf],空集,的一種。所以過程中求交求並不會有奇怪情況。
求並的時候sort一下就好了。
然後floyd,從1到u到x的u的區間求交。
雖然不是所有的負環上的點都會考慮到,但是每個負環上至少有乙個點可以得到限制,使得沒有負環。
最後是求交,所以不影響正確性。
UOJ 192 UR 14 最強跳蚤
題目鏈結 暑期課第二天 樹上問題高階 具體內容看筆記部落格吧 題意n個節點的樹t 邊有邊權w 求滿足 u,v 上所有邊權乘積為完全平方數的路徑有多少條 看到 所有邊權乘積為完全平方數 想到完全平方數的特殊性 就是分解質因數後 質因數指數都為偶數 然後就想到分解邊權質因數 判質路徑邊權奇偶性 後者由於...
UOJ 192 UR 14 最強跳蚤
這道題本來不想寫部落格的 但是鑑於自己犯了低階錯誤,還是寫篇部落格記載一下。一開始我的想法和題解裡面的演算法而比較類似,也是先分解質因數,然後用質因子是否出現偶數次來判斷當前這個數是否是完全平方數 然而這樣並不能ac,於是我去翻了題解 get 了乙個新做法,就是給每個出現過的質因子賦乙個 0,2 的...
樹狀陣列2(破壞公路)
題目描述 在太平洋中心有乙個圓形小島,沿著小島的海岸線分布著 n個小鎮,編號分別為 1,2,3 n 小鎮i 1 小鎮i 小鎮i 1 是相鄰的 當然小鎮 n與小鎮 1相鄰 相鄰小鎮之間存在一條公路,公路也有編號,公路 i連線小鎮 i和小鎮 i 1,公路 n連線小鎮 n和小鎮 1.現在對小島有 m個操作...