题意:
给出一个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; }
原文地址:http://blog.csdn.net/ww140142/article/details/47778229