校内模拟赛 旅行(by NiroBC)
Posted mjtcn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了校内模拟赛 旅行(by NiroBC)相关的知识,希望对你有一定的参考价值。
题意:
n个点的无向图,Q次操作,每次操作可以连接增加一条边,询问两个点之间有多少条边是必经之路。如果不连通,输出-1。
分析:
首先并查集维护连通性,每次加入一条边后,如果这条边将会连接两个联通块,那么lct连接两个点,边权化为点权,新增一个点,点权为1。否则,构成了环,环上的边都变为0,lct维护覆盖标记。询问就是对一条链进行询问。
离线+树剖的做法:从前往后建出树,如果出现环则不加入,然后树剖,每次出现一条非树边就是将环上的边赋值为0,询问就是两点之间的边权和。
代码:
lct
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cctype> #include<cmath> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f; } const int N = 200005; struct LCT{ #define lc ch[rt][0] #define rc ch[rt][1] int siz[N], val[N], ch[N][2], fa[N], sk[N], rev[N], tag[N], Index; inline bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; } inline bool son(int x) { return x == ch[fa[x]][1]; } inline void pushup(int rt) { siz[rt] = siz[lc] + siz[rc] + val[rt]; } inline void pushdown(int rt) { if (rev[rt]) { swap(lc, rc); rev[lc] ^= 1, rev[rc] ^= 1; rev[rt] ^= 1; } if (tag[rt]) { tag[lc] = tag[rc] = 1; siz[lc] = siz[rc] = val[lc] = val[rc] = tag[rt] = 0; } } void rotate(int x) { int y = fa[x], z = fa[y], c = son(y), b = son(x), a = ch[x][!b]; if (!isroot(y)) ch[z][c] = x; fa[x] = z; ch[x][!b] = y, fa[y] = x; ch[y][b] = a; if (a) fa[a] = y; pushup(y); pushup(x); } void splay(int x) { int top = 1; sk[top] = x; for (int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i]; while (top) pushdown(sk[top --]); // 注意下pushdown到x的下一层 while (!isroot(x)) { int y = fa[x], z = fa[y]; if (isroot(y)) rotate(x); else { if (son(x) == son(y)) rotate(y), rotate(x); else rotate(x), rotate(x); } } } void access(int x) { for (int last = 0; x; last = x, x = fa[x]) splay(x), ch[x][1] = last, pushup(x); } void makeroot(int x) { access(x); splay(x); rev[x] ^= 1; } void link(int x,int y) { makeroot(x); fa[x] = y; } void add(int x,int y) { val[++Index] = 1; link(x, Index); link(Index, y); } void split(int x,int y) { makeroot(x); access(y); splay(y); } #undef lc #undef rc }lct; int fa[N]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() { int n = read(), m = read(); lct.Index = n; for (int i = 1; i <= n; ++i) fa[i] = i; while (m --) { int opt = read(), x = read(), y = read(), tx = find(x), ty = find(y); if (opt == 1) { if (tx != ty) fa[tx] = ty, lct.add(x, y); else lct.split(x, y), lct.tag[y] = 1, lct.val[y] = lct.siz[y] = 0; } else { if (tx != ty) puts("-1"); else lct.split(x, y), printf("%d\n", lct.siz[y]); } } return 0; }
以上是关于校内模拟赛 旅行(by NiroBC)的主要内容,如果未能解决你的问题,请参考以下文章