Description
给定一些点和带权无向边,要求资瓷一下操作
1:删掉一条边(x,y)
2:查询x到y路径上最大权的最小值(绕
【加强版数据范围】
N ≤ 100000
M ≤ 1000000
Q ≤ 100000
Solution
如果没有修改那么就是最小生成树+倍增,现在多了修改但是只有删除操作,考虑离线询问并倒序
一个我没见过的骚操作就是用LCT维护MST,每次加边(x,y)就找到两点间的最大权所在边(x,y)’,断掉然后连新边即可
需要注意的是LCT只能维护点权,因此需要把边拆成点,即对于一条形如(x,y)的边拆成(x,mid,y)这样,把边权放在mid上就ok
注意空间问题和不要瞎jb乱splay,毕竟人丑自带大常数
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;i--)
const int N=100005;
const int E=1000005;
struct treeNode {int son[2],fa,v,max; bool rev,is_root;} t[N*2+E];
struct edge {int x,y,w,id; bool used;} e[N*2+E];
struct Q {int x,y,w,id,ans;} q[N*2];
int fa[N+E],n,m;
inline int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
inline void write(int x){
char ch[21]={}; int i=0;
if (x<0) putchar('-');
do {ch[++i]='0'+x%10;} while (x/=10);
while (i) putchar(ch[i--]);
putchar('\n');
}
void push_down(int x) {
if (!t[x].rev||!x) return ;
std:: swap(t[x].son[0],t[x].son[1]);
if (t[x].son[0]) t[t[x].son[0]].rev^=1;
if (t[x].son[1]) t[t[x].son[1]].rev^=1;
t[x].rev=0;
}
void push_up(int x) {
t[x].max=std:: max(t[x].v,std:: max(t[t[x].son[0]].max,t[t[x].son[1]].max));
}
void rotate(int x) {
if (t[x].is_root) return ;
int y=t[x].fa; int z=t[y].fa;
int k=t[y].son[1]==x;
t[y].son[k]=t[x].son[!k];
if (t[x].son[!k]) t[t[x].son[!k]].fa=y;
t[x].son[!k]=y;
t[y].fa=x; t[x].fa=z;
if (t[y].is_root) {
t[x].is_root=1;
t[y].is_root=0;
} else t[z].son[t[z].son[1]==y]=x;
push_up(y); push_up(x);
}
void remove(int x) {
if (!t[x].is_root) remove(t[x].fa);
push_down(x);
}
void splay(int x,int goal=0) {
remove(x);
while (!t[x].is_root) {
int y=t[x].fa; int z=t[y].fa;
if (!t[y].is_root) {
if ((t[z].son[1]==y)^(t[y].son[1]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x) {
int y=0;
do {
splay(x);
t[t[x].son[1]].is_root=1;
t[t[x].son[1]=y].is_root=0;
push_up(x);
y=x; x=t[x].fa;
} while (x);
}
void mroot(int x) {
access(x); splay(x); t[x].rev^=1;
}
void link(int x,int y) {
mroot(x); t[x].fa=y;// splay(x);
}
void cut(int x,int y) {
mroot(x); access(y); splay(y);
t[x].fa=t[y].son[0]=0;
t[x].is_root=1;
push_up(y);
}
int get_father(int x) {
if (!fa[x]) return x;
return fa[x]=get_father(fa[x]);
}
int query(int x,int y) {
mroot(x); access(y); splay(y);
while (t[t[y].son[0]].max==t[y].max||t[t[y].son[1]].max==t[y].max) {
y=t[y].son[t[t[y].son[1]].max>t[t[y].son[0]].max];
}
return y;
}
int find(int x,int y) {
int l=1,r=m;
while (l<=r) {
int mid=(l+r)>>1;
if (e[mid].x==x&&e[mid].y==y) return mid;
if (x<e[mid].x||e[mid].x==x&&y<e[mid].y) r=mid-1;
else l=mid+1;
}
}
bool cmp1(edge a,edge b) {
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
bool cmp2(edge a,edge b) {
return a.w<b.w;
}
int main(void) {
n=read(); m=read(); int T=read();
rep(i,1,n+m) t[i].is_root=1;
rep(i,1,m) {
e[i].x=read(); e[i].y=read(); e[i].w=read();
if (e[i].x>e[i].y) std:: swap(e[i].x,e[i].y);
}
std:: sort(e+1,e+m+1,cmp1);
rep(i,1,m) {
t[i+n].max=t[i+n].v=e[i].w;
e[i].id=i;
}
rep(i,1,T) {
q[i].w=read(); q[i].x=read(); q[i].y=read();
if (q[i].x>q[i].y) std:: swap(q[i].x,q[i].y);
q[i].id=find(q[i].x,q[i].y);
if (q[i].w==2) e[q[i].id].used=1;
}
std:: sort(e+1,e+m+1,cmp2);
rep(i,1,m) if (!e[i].used&&get_father(e[i].x)!=get_father(e[i].y)) {
fa[get_father(e[i].x)]=get_father(e[i].y);
link(e[i].x,e[i].id+n); link(e[i].y,e[i].id+n);
}
std:: sort(e+1,e+m+1,cmp1);
drp(i,T,1) {
int tmp=query(q[i].x,q[i].y);
if (q[i].w==1) q[i].ans=t[tmp].max;
else if (t[tmp].max>e[q[i].id].w) {
cut(e[tmp-n].x,tmp); cut(e[tmp-n].y,tmp);
link(e[q[i].id].x,q[i].id+n); link(e[q[i].id].y,q[i].id+n);
}
}
rep(i,1,T) if (q[i].w==1) write(q[i].ans);
return 0;
}