增量最小生成树
吐槽:
动态加减边
LCT真难调。。
注意cut的写法:
先Evert(u)
再Access(v)
splay(v)
这样u->v就是一条重链,把v的左儿子和u的父亲赋为0就可以断掉边了
二分写错了啊!!
增量最小生成树
把删边倒流成加边
恩,思路是先Kruscal,不包含删掉的边(二分)
然后再添边找环
断最大的边就好了
同类题目:NOI魔法森林
#include
#include
#include
#include
#include
#define maxn 200010
#define Edge(u) u + n
using namespace std;
int n, m;
int getint()
{
char ch = getchar();
for ( ; ch > '9' || ch < '0'; ch = getchar());
int tmp = 0;
for ( ; '0' <= ch && ch <= '9'; ch = getchar())
tmp = tmp * 10 + int(ch) - 48;
return tmp;
}
struct EG{
int u, v, w;
bool flag;
inline void read(){
u = getint();
v = getint();
w = getint();
if(u > v)swap(u, v);
}
void print(){
printf("%d %d %d\n", u, v, w);
}
}G[1000010];
bool cmpuv(const EG& a, const EG& b){
if(a.u != b.u)return a.u < b.u;
if(a.v != b.v)return a.v < b.v;
return a.w < b.w;
}
bool cmpw(const EG& a, const EG& b){
return a.w < b.w;
}
int Lower_bound(int u, int v){
int l = 1, r = m;
while(l < r){
int mid = l + r >> 1;
if(G[mid].u == u){
if(G[mid].v == v)return mid;
if(v < G[mid].v)r = mid;
else l = mid + 1;
}
else if(u < G[mid].u)r = mid;
else l = mid + 1;
}
return r;
}
struct Question{
int type, u, v;
inline void read(){
type = getint();
u = getint();
v = getint();
if(u > v)swap(u, v);
}
}q[maxn];
int p[maxn];
int val[maxn], c[maxn][2], fa[maxn], pos[maxn];
int L[maxn], R[maxn];
const int inf = 0x7fffffff;
bool rev[maxn];
namespace Splay{
#define l c[x][0]
#define r c[x][1]
int st[maxn], top;
void pushup(int x){
pos[x] = x;
if(val[pos[x]] < val[pos[l]])
pos[x] = pos[l];
if(val[pos[x]] < val[pos[r]])
pos[x] = pos[r];
}
void pushdown(int x){
if(rev[x]){
rev[x] = 0;
if(l)rev[l] ^= 1;
if(r)rev[r] ^= 1;
swap(l, r);
}
}
bool isroot(int x){
return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
void rotate(int p, int x){
int mark = p == c[x][1], y = c[p][mark ^ 1];
int z = fa[x];
if(x == c[z][0])c[z][0] = p;
if(x == c[z][1])c[z][1] = p;
if(y)fa[y] = x;
fa[p] = z; c[p][mark ^ 1] = x;
fa[x] = p; c[x][mark] = y;
pushup(x);
}
void splay(int p){
st[++ top] = p;
for(int i = p; !isroot(i); i = fa[i])
st[++ top] = fa[i];
while(top)
pushdown(st[top --]);
while(!isroot(p)){
int x = fa[p], y = fa[x];
if(isroot(x))rotate(p, x);
else if(p == c[x][0] ^ x == c[y][0])
rotate(p, x), rotate(p, y);
else rotate(x, y), rotate(p, x);
}
pushup(p);
}
#undef l
#undef r
}
namespace LCT{
void Access(int u){
int t = 0;
while(u){
Splay::splay(u);
c[u][1] = t;
t = u;
u = fa[u];
}
}
void Evert(int u){
Access(u);
Splay::splay(u);
rev[u] ^= 1;
Splay::pushdown(u);
}
void link(int u, int v, int t){
Evert(v);
fa[v] = t;
Evert(t);
fa[t] = u;
}
void cut(int u, int v, int t){
Evert(t);
Access(v);
Splay::splay(v);
c[v][0] = fa[t] = 0;
swap(u, v);
Evert(t);
Access(v);
Splay::splay(v);
c[v][0] = fa[t] = 0;
}
int ask(int u, int v){
Evert(u);
Access(v);
Splay::splay(v);
//cout <<"debug: "<< u << ' ' << v << ' ' << pos[v] << ' ' << val[7] << endl;
return pos[v];
}
}
namespace Kruscal{
int fa[maxn];
struct Edge_{
int to, next, dis;
}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v, int d){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
edge[cnt].dis = d;
h[u] = cnt;
swap(u, v);
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
edge[cnt].dis = d;
h[u] = cnt;
}
int getfa(int x){
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
void dfs(int u){
for(int i = h[u]; i; i = edge[i].next){
int v = edge[i].to;
if(v == fa[u])continue;
fa[v] = u;
val[Edge(v)] = edge[i].dis;
L[Edge(v)] = u;
R[Edge(v)] = v;
LCT::link(u, v, Edge(v));
dfs(v);
}
}
void work(){
sort(G + 1, G + 1 + m, cmpw);
for(int i = 1; i <= n; i ++)
fa[i] = i;
int C = 0;
for(int i = 1; i <= m; i ++){
if(G[i].flag)continue;
int u = getfa(G[i].u), v = getfa(G[i].v);
if(u != v){
C ++;
fa[u] = v;
add(G[i].u, G[i].v, G[i].w);
if(C == n - 1)break;
}
}
for(int i = 0; i <= n + 1; i ++)
val[i] = -inf;
fa[1] = 0;
for(int i = 1; i <= 2 * n; i ++)
pos[i] = i;
dfs(1);
}
}
int ans[maxn];
int main(){
int Q;
scanf("%d%d%d", &n, &m, &Q);
for(int i = 1; i <= m; i ++)
G[i].read();
sort(G + 1, G + 1 + m, cmpuv);
for(int i = 1; i <= Q; i ++){
q[i].read();
if(q[i].type == 2){
int t = Lower_bound(q[i].u, q[i].v);
p[i] = G[t].w;
G[t].flag = true;
}
}
Kruscal::work();
for(int i = Q; i >= 1; i --){
int t = LCT::ask(q[i].u, q[i].v);
//if(i == 1531)cout << q[i].type;
if(q[i].type == 1)
ans[i] = val[t];
else{
if(val[t] > p[i]){
LCT::cut(L[t], R[t], t);
val[t] = p[i];
pos[t] = t;
rev[t] = c[t][0] = c[t][1] = fa[t] = 0;
L[t] = q[i].u, R[t] = q[i].v;
LCT::link(q[i].u, q[i].v, t);
}
}
}
for(int i = 1; i <= Q; i ++)
if(q[i].type == 1)
printf("%d\n", ans[i]);
return 0;
}