题意:
给出一个n个点m条边的无向图,边上有权值;
Q次询问,每次有两种操作:
1.求x,y两点路径上的最大值的最小值;
2.删除一条边;
保证删除的边存在,保证图时刻连通,保证不会出现重边和自环;
n≤100000,m≤1000000,Q≤100000;
题解:
这是一个动态图问题,但是由于询问操作的特殊性,我们也可以转化到树上做;
仔细看看不就是带删边的货车运输吗!
那么用LCT来维护最小生成树查询操作1就可以了;
但是LCT维护最小生成树是不能删边的;
考虑倒着处理询问,删边就成了加边;
加边会出现环,那么就将权值最大的边弹出去就好了;
弹边操作似乎比较恶心,那么将边转化成一个点,这个点连接两个点;
那么就把边权转化到点上,删除这个点的两条边就是了;
此题预处理比较糟糕(似乎离线处理的东西都这样);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define Pt 330000
#define which(x) (ch[fa[x]][1]==x)
using namespace std;
struct node
{
bool op;
int x,y,val,no;
}Q[N];
struct edge
{
int x,y,val;
bool del;
friend bool operator <(edge a,edge b)
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
}total[N*10],temp;
int fa[Pt],ch[Pt][2],val[Pt],ma[Pt],wma[Pt],ans[N],f[N];
bool rt[Pt],rev[Pt];
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
int cmp(edge a,edge b)
{
if(a.del==b.del)
return a.val<b.val;
return a.del<b.del;
}
void Pushup(int x)
{
ma[x]=max(val[x],max(ma[ch[x][0]],ma[ch[x][1]]));
wma[x]=ma[x]==val[x]?x:(ma[x]==val[wma[ch[x][0]]]?wma[ch[x][0]]:wma[ch[x][1]]);
}
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void Pushdown(int x)
{
if(rev[x])
{
reverse(ch[x][0]);
reverse(ch[x][1]);
rev[x]=0;
}
}
void down(int x)
{
if(!rt[x]) down(fa[x]);
Pushdown(x);
}
void Rotate(int x)
{
int f=fa[x];
bool k=which(x);
if(rt[f]) rt[f]^=rt[x]^=1;
else ch[fa[f]][which(f)]=x;
ch[f][k]=ch[x][!k];
ch[x][!k]=f;
fa[ch[f][k]]=f;
fa[x]=fa[f];
fa[f]=x;
Pushup(f);
Pushup(x);
}
void Splay(int x)
{
down(x);
while(!rt[x])
{
int f=fa[x];
if(rt[f])
{
Rotate(x);
return ;
}
if(which(x)^which(f))
Rotate(x);
else
Rotate(f);
Rotate(x);
}
}
void access(int x)
{
int y=0;
while(x)
{
Splay(x);
rt[ch[x][1]]=1,rt[y]=0;
ch[x][1]=y;
Pushup(x);
y=x,x=fa[x];
}
}
void Mtr(int x)
{
access(x);
Splay(x);
reverse(x);
}
void Link(int x,int y)
{
Mtr(x);
fa[x]=y;
}
void Cut(int t,int x,int y)
{
Mtr(t);
access(x);
Splay(t);
rt[ch[t][1]]=1;
fa[ch[t][1]]=0;
ch[t][1]=0;
access(y);
Splay(t);
rt[ch[t][1]]=1;
fa[ch[t][1]]=0;
ch[t][1]=0;
Pushup(t);
}
int get_max(int x,int y)
{
Mtr(x);
access(y);
Splay(x);
return ma[x];
}
int get_wmax(int x,int y)
{
Mtr(x);
access(y);
Splay(x);
return wma[x];
}
int find(int x)
{
return f[x]==x?x:find(f[x]);
}
void Build_Min_Tree(int n,int m)
{
sort(total+1,total+m+1,cmp);
for(int i=1;i<=n;i++)
f[i]=i;
int cnt=0;
for(int i=1;i<=m;i++)
{
int x=find(total[i].x),y=find(total[i].y);
if(x!=y)
{
f[x]=y;
swap(total[i],total[++cnt]);
if(cnt==n-1)
break;
}
}
}
int main()
{
int n,m,q,i,j,k,cnt1,cnt2,op,x,y,v;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=m;i++)
{
total[i].x=read(),total[i].y=read(),total[i].val=read();
if(total[i].x>total[i].y)
swap(total[i].x,total[i].y);
}
sort(total+1,total+1+m);
for(i=1,cnt1=cnt2=0;i<=q;i++)
{
op=read();
if(op==1)
Q[i].x=read(),Q[i].y=read(),Q[i].no=++cnt1;
else
{
Q[i].op=1;
Q[i].x=read(),Q[i].y=read();
if(Q[i].x>Q[i].y) swap(Q[i].x,Q[i].y);
temp.x=Q[i].x,temp.y=Q[i].y;
k=lower_bound(total+1,total+m+1,temp)-total;
total[k].del=1,Q[i].val=total[k].val;
Q[i].no=++cnt2;
}
}
Build_Min_Tree(n,m);
for(i=1;i<=n;i++)
rt[i]=1,wma[i]=i;
for(i=1;i<n;i++)
{
rt[i+n]=1,wma[i+n]=i+n,val[i+n]=ma[i+n]=total[i].val;
Link(i+n,total[i].x);
Link(i+n,total[i].y);
}
for(i=q;i>=1;i--)
{
if(Q[i].op)
{
x=Q[i].x,y=Q[i].y;
rt[Q[i].no+(n<<1)]=1,wma[Q[i].no+(n<<1)]=Q[i].no+(n<<1);
val[Q[i].no+(n<<1)]=ma[Q[i].no+(n<<1)]=Q[i].val;
k=get_wmax(x,y);
if(val[k]>Q[i].val)
{
Cut(k,x,y);
Link(Q[i].no+(n<<1),x);
Link(Q[i].no+(n<<1),y);
}
}
else
{
ans[Q[i].no]=get_max(Q[i].x,Q[i].y);
}
}
for(i=1;i<=cnt1;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}