這裡提供幾種不用腦子的演算法(當然是離線的):
$\text$
記下每條邊的刪除時間,用$\text$維護最大生成樹,每次加進一條邊時,跟原來那條鏈上的做比較,刪除那條刪除時間最短的邊即可。
線段樹分治
這個演算法將每條邊的加入和刪除時間加入到線段樹中,所以在遍歷到葉子節點時,那個時刻存在的邊都已經在並查集上了,於是直接判斷即可。
並查集用按秩合併就可以了,撤銷時記得按棧序撤銷。
lct找$hyj$去
線段樹分治
我的寫法可能(比較好看)並沒有建線段樹......
#include#include#include#include#include#include#define rg register
#define clear(x, y) memset(x, y, sizeof(x))
inline int read()
const int maxn(200010);
struct edge ;
std::pairq[maxn], stk[maxn << 2];
std::vectore;
std::mapg[maxn];
int fa[maxn], top, q_num, n, id[2][maxn], cnt, size[maxn];
char s[10];
inline int find(int x)
inline void merge(int x, int y)
inline void undo()
inline void div(int l, int r, std::vectore)
if(l == r) printf("%c\n", find(q[l].first) == find(q[l].second) ? 'y' : 'n');
else div(l, mid, l), div(mid + 1, r, r);
while(top > tmp) undo();
}int main()
); g[id[r1][c1]][id[r2][c2]] = g[id[r2][c2]][id[r1][c1]] = e.size() - 1;
} else if(s[0] == 'c') e[g[id[r1][c1]][id[r2][c2]]].end = q_num;
else if(s[0] == 'a') q[++q_num] = std::make_pair(id[r1][c1], id[r2][c2]);
} for(std::vector::iterator it = e.begin(); it != e.end(); ++it)
if(it -> end == -1) it -> end = q_num;
for(rg int i = 1; i <= n + n; i++) fa[i] = i, size[i] = 1;
div(1, q_num, e);
return 0;
}
SHOI2008 堵塞的交通
有一篇超級棒的線段樹 大力分類討論的題解!戳我 可是我還是不會寫這個做法qwqwqwq 這裡提供線段樹分治的寫法。感覺比較不需要智商,就是跑的有點慢了。include include include include include include include include define max...
SHOI2008 堵塞的交通
有一天,由於某種穿越現象作用,你來到了傳說中的小人國。小人國的布局非常奇特,整個國家的交通系統可 以被看成是乙個2行c列的矩形網格,網格上的每個點代表乙個城市,相鄰的城市之間有一條道路,所以總共有2c個 城市和3c 2條道路。小人國的交通狀況非常槽糕。有的時候由於交通堵塞,兩座城市之間的道路會變得不...
SHOI2008 堵塞的交通
題目描述 有一天,由於某種穿越現象作用,你來到了傳說中的小人國。小人國的布局非常奇特,整個國家的交通系統可 以被看成是乙個2行c列的矩形網格,網格上的每個點代表乙個城市,相鄰的城市之間有一條道路,所以總共有2c個 城市和3c 2條道路。小人國的交通狀況非常槽糕。有的時候由於交通堵塞,兩座城市之間的道...