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;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9237635.html
今日推荐