bzoj 2594 [Wc2006]水管局长数据加强版
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2594
据说写得丑会TLE。反正我T了好久……
这道题时间倒流一下就是 bzoj3669魔法森林 了。
0.我好……呀,竟然没深入想想应该是二分找到每个询问对应的边!
*1.一开始的加边要按kruscal的方式,就要按边权排序;可为了二分还要按x、y排序。这时对于标号的处理需要费一番心机。(反正我是抄hzwer的)
**2.query要写成 int 的,不要写成 void 的再在主函数里调用mx[后一项]。反正如果那样就会TLE!!!可能也和在makeroot里用了void的query有关?
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,M=1e6+5; int n,m,Q,fa[N],pre[N+M],val[N+M],c[N+M][2],mx[N+M],stack[N+M],top,ans[N],cnt; bool rev[N+M]; struct Ed{ int x,y,w,bh;bool vis; bool operator< (const Ed &k)const{return w<k.w;} }ed[M]; struct Ques{ int op,x,y,e; }q[N]; int rdn() { int ret=0,fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=-1;ch=getchar();} while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar(); return ret*fx; } bool cmp(Ed u,Ed v){return u.x==v.x?u.y<v.y:u.x<v.x;} bool cmp2(Ed u,Ed v){return u.bh<v.bh;} int fd(int x,int y) { int l=1,r=m,ret=0; while(l<=r) { int mid=((l+r)>>1); if(ed[mid].x>x||(ed[mid].x==x&&ed[mid].y>=y))ret=mid,r=mid-1; else l=mid+1; } return ret; } int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;} void pshp(int x) { mx[x]=x; if(val[mx[c[x][0]]]>val[mx[x]])mx[x]=mx[c[x][0]]; if(val[mx[c[x][1]]]>val[mx[x]])mx[x]=mx[c[x][1]]; } void reverse(int x) { if(rev[x]){ rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); rev[x]=0; } } void rotate(int x) { int y=pre[x],z=pre[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; pre[x]=z;pre[y]=x; c[y][d]=c[x][!d];pre[c[x][!d]]=y;c[x][!d]=y; pshp(y);pshp(x); } void splay(int x) { stack[top=1]=x; for(int t=x;!isroot(t);t=pre[t])stack[++top]=pre[t]; //用t…… for(;top;top--)reverse(stack[top]); for(;!isroot(x);rotate(x)) { int y=pre[x],z=pre[y]; if(isroot(y))continue; ((y==c[z][0])^(x==c[y][0]))?rotate(x):rotate(y); } pshp(x);//? } void access(int x) { for(int t=0;x;c[x][1]=t,t=x,x=pre[x])splay(x);//这里不是!isroot(x)!!! } void makeroot(int x) { access(x);splay(x);rev[x]^=1; } void link(int x,int y) { makeroot(x);pre[x]=y; } int query(int x,int y) //当前辅助树中只有x、y之间的链! { makeroot(x);access(y);splay(y);return mx[y]; } void cut(int x,int y) //当前辅助树中只有x、y两个点!(因为取出链,但有直接边) { makeroot(x);access(y);splay(y); pre[x]=0;c[y][0]=0; } int main() { n=rdn();m=rdn();Q=rdn(); for(int i=1;i<=m;i++) { ed[i].x=rdn();ed[i].y=rdn();ed[i].w=rdn(); if(ed[i].x>ed[i].y)swap(ed[i].x,ed[i].y); } sort(ed+1,ed+m+1); for(int i=1;i<=m;i++) ed[i].bh=i,val[i+n]=ed[i].w; sort(ed+1,ed+m+1,cmp); for(int i=1;i<=Q;i++) { q[i].op=rdn();q[i].x=rdn();q[i].y=rdn(); if(q[i].op==1)continue;///// if(q[i].x>q[i].y)swap(q[i].x,q[i].y); int k=fd(q[i].x,q[i].y); q[i].e=ed[k].bh;ed[k].vis=1; } for(int i=1;i<=n;i++)fa[i]=i; sort(ed+1,ed+m+1,cmp2);int tot=0; for(int i=1;i<=m;i++) if(!ed[i].vis){ int u=ed[i].x,v=ed[i].y; if(find(u)!=find(v)){ fa[find(u)]=find(v);link(i+n,u);link(i+n,v);tot++; if(tot==n-1)break; } } for(int i=Q;i;i--) { if(q[i].op==1)ans[++cnt]=val[query(q[i].x,q[i].y)];//val[] else { int k=q[i].e,u=ed[k].x,v=ed[k].y; int t=query(u,v);if(val[t]<=ed[k].w)continue; cut(t,ed[t-n].x);cut(t,ed[t-n].y); link(k+n,u);link(k+n,v); } } for(int i=cnt;i;i--)printf("%d\n",ans[i]); return 0; }