BZOJ 2594: [Wc2006]水管局长数据加强版 [LCT kruskal]

2594: [Wc2006]水管局长数据加强版

Time Limit: 25 Sec  Memory Limit: 128 MB
Submit: 2917  Solved: 918
[Submit][Status][Discuss]

Description

SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了。嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项。
在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于MY市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
不妨将MY市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。
 

Input

输入文件第一行为3个整数:N, M, Q分别表示管道连接处(结点)的数目、目前水管(无向边)的数目,以及你的程序需要处理的任务数目(包括寻找一条满足要求的路径和接受某条水管坏掉的事实)。
以下M行,每行3个整数x, y和t,描述一条对应的水管。x和y表示水管两端结点的编号,t表示准备送水所需要的时间。我们不妨为结点从1至N编号,这样所有的x和y都在范围[1, N]内。
以下Q行,每行描述一项任务。其中第一个整数为k:若k=1则后跟两个整数A和B,表示你需要为供水公司寻找一条满足要求的从A到B的水管路径;若k=2,则后跟两个整数x和y,表示直接连接x和y的水管宣布报废(保证合法,即在此之前直接连接x和y尚未报废的水管一定存在)。
 

Output

按顺序对应输入文件中每一项k=1的任务,你需要输出一个数字和一个回车/换行符。该数字表示:你寻找到的水管路径中所有管道全都完成准备工作所需要的时间(当然要求最短)。
 

Sample Input

4 4 3
1 2 2
2 3 3
3 4 2
1 4 2
1 1 4
2 1 4
1 1 4

Sample Output

2
3

【原题数据范围】
N ≤ 1000
M ≤ 100000
Q ≤ 100000
测试数据中宣布报废的水管不超过5000条;且任何时候我们考虑的水管网络都是连通的,即从任一结点A必有至少一条水管路径通往任一结点B。

【加强版数据范围】
N ≤ 100000
M ≤ 1000000
Q ≤ 100000
任何时候我们考虑的水管网络都是连通的,即从任一结点A必有至少一条水管路径通往任一结点B。

手残毁一生
 
显然要动态维护最小生成树,用LCT
有两个问题:
1.LCT怎么维护边权每条边变为一个点连接边的两个端点
2.Kruskal不支持删边吧BZOJ1015一样的思想,常用技巧是离线倒序处理,加边很简单了当前必定有一个环,比较环上最大边与要加的边
PS:我不会告诉你在我眼中左上面的颜色是红色的
 
友情提示: 简单无向图且保持连通哦
 
注意:
1.加边的时候要删除的边(点)和要加入的连接的端点会不一样
2.多条边w可能相同,最后要按id排序
3.二分写对啊二分写对啊二分写对啊二分写对啊二分写对啊二分写对啊 RE一片
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=15e5+5,NN=1e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,Q;

struct node{
    int ch[2],fa,rev,mx,mxp,w;
}t[N];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void update(int x){
    t[x].mx=t[x].w;t[x].mxp=x;
    if(t[lc].mx>t[x].mx) t[x].mx=t[lc].mx,t[x].mxp=t[lc].mxp;
    if(t[rc].mx>t[x].mx) t[x].mx=t[rc].mx,t[x].mxp=t[rc].mxp;
}
inline void rever(int x){
    t[x].rev^=1;
    swap(lc,rc);
}
inline void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);
        t[x].rev=0;    
    }
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);
    
    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}

inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeR(int x){
    Access(x);splay(x);
    rever(x);
}
inline int FindR(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeR(x);
    t[x].fa=y;
}
inline void Cut(int x,int y){
    MakeR(x);Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
    update(y);//!!!
}
inline void Split(int x,int y){
    MakeR(x);Access(y);splay(y);
}

int del[N];
struct edge{
    int u,v,w,id;
    bool operator <(const edge &e)const{return w<e.w;}
}e[N];
inline bool cmpuv(edge a,edge b){
    return a.u<b.u||(a.u==b.u&&a.v<b.v);
}
inline bool cmpid(edge a,edge b){
    return a.id<b.id;
}
int bs(int u,int v){
    int l=1,r=m;
    while(l<=r){
        int mid=(l+r)>>1;
        if(e[mid].u==u&&e[mid].v==v) return mid;
        else if(e[mid].u<u||(e[mid].u==u&&e[mid].v<v)) l=mid+1;
        else r=mid-1;
    }
    return 0;
}
struct ques{
    int op,x,y,del,ans;
}q[NN];
int fa[N];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void solve(){
    for(int i=1;i<=n;i++) fa[i]=i;
    sort(e+1,e+1+m,cmpid);
    int tot=0;
    for(int i=1;i<=m;i++) if(!del[i]){ 
        int x=find(e[i].u),y=find(e[i].v);//printf("hieid %d %d  %d %d
",i,e[i].id,x,y);
        if(x!=y){
            Link(e[i].u,i+n);Link(e[i].v,i+n);
            fa[x]=y;
            tot++;
            if(tot==n-1) break;
        }
    }
    
    for(int i=Q;i>=1;i--){
        int x=q[i].x,y=q[i].y;
        if(q[i].op==1){
            Split(x,y);
            q[i].ans=t[y].mx;//printf("ans %d %d
",i,t[y].mx);
        }else{
            int k=q[i].del;//try to add e[k]
            Split(x,y);
            if(e[k].w<t[y].mx){
                int p=t[y].mxp;//printf("replace %d %d
",p-n,k);
                Cut(e[p-n].u,p);Cut(e[p-n].v,p);
                Link(x,k+n);Link(y,k+n);
            }
        }
    }
    for(int i=1;i<=Q;i++) if(q[i].op==1) printf("%d
",q[i].ans);
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();Q=read();
    for(int i=1;i<=m;i++){
        e[i].u=read(),e[i].v=read(),e[i].w=read();
        if(e[i].u>e[i].v) swap(e[i].u,e[i].v);
    }
    sort(e+1,e+1+m);
    for(int i=1;i<=m;i++){//printf("e %d  %d %d %d
",i,e[i].u,e[i].v,e[i].w);
        e[i].id=i;
        t[n+i].w=t[n+i].mx=e[i].w;
        t[n+i].mxp=n+i;
    }
    sort(e+1,e+1+m,cmpuv);
    for(int i=1;i<=Q;i++){
        q[i].op=read(),q[i].x=read(),q[i].y=read();
        if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
        if(q[i].op==2){
            int k=e[bs(q[i].x,q[i].y)].id;
            del[k]=1;//printf("del %d
",k);
            q[i].del=k;
        }
    }
    solve();
}

LCT直接保存最大编号也可以

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=15e5+5,NN=1e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,Q;

struct node{
    int ch[2],fa,rev,mxp;
}t[N];
int val[N];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void update(int x){
    t[x].mxp=x;
    if(val[t[lc].mxp]>val[t[x].mxp]) t[x].mxp=t[lc].mxp;
    if(val[t[rc].mxp]>val[t[x].mxp]) t[x].mxp=t[rc].mxp;
}
inline void rever(int x){
    t[x].rev^=1;
    swap(lc,rc);
}
inline void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);
        t[x].rev=0;    
    }
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);
    
    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}

inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeR(int x){
    Access(x);splay(x);
    rever(x);
}
inline int FindR(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeR(x);
    t[x].fa=y;
}
inline void Cut(int x,int y){
    MakeR(x);Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
    update(y);//!!!
}
inline void Split(int x,int y){
    MakeR(x);Access(y);splay(y);
}
inline int Que(int x,int y){
    MakeR(x);Access(y);splay(y);
    return t[y].mxp;
}

int del[N];
struct edge{
    int u,v,w,id;
    bool operator <(const edge &e)const{return w<e.w;}
}e[N];
inline bool cmpuv(edge a,edge b){
    return a.u<b.u||(a.u==b.u&&a.v<b.v);
}
inline bool cmpid(edge a,edge b){
    return a.id<b.id;
}
int bs(int u,int v){
    int l=1,r=m;
    while(l<=r){
        int mid=(l+r)>>1;
        if(e[mid].u==u&&e[mid].v==v) return mid;
        else if(e[mid].u<u||(e[mid].u==u&&e[mid].v<v)) l=mid+1;
        else r=mid-1;
    }
    return 0;
}
struct ques{
    int op,x,y,del,ans;
}q[NN];
int fa[N];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void solve(){
    for(int i=1;i<=n;i++) fa[i]=i;
    sort(e+1,e+1+m,cmpid);
    int tot=0;
    for(int i=1;i<=m;i++) if(!del[i]){ 
        int x=find(e[i].u),y=find(e[i].v);//printf("hieid %d %d  %d %d
",i,e[i].id,x,y);
        if(x!=y){
            Link(e[i].u,i+n);Link(e[i].v,i+n);
            fa[x]=y;
            tot++;
            if(tot==n-1) break;
        }
    }
    
    for(int i=Q;i>=1;i--){
        int x=q[i].x,y=q[i].y;
        if(q[i].op==1){
            int p=Que(x,y);
            q[i].ans=val[p];//printf("ans %d %d
",i,t[y].mx);
        }else{
            int k=q[i].del;//try to add e[k]
            int p=Que(x,y);
            if(e[k].w<val[p]){
                Cut(e[p-n].u,p);Cut(e[p-n].v,p);
                Link(x,k+n);Link(y,k+n);
            }
        }
    }
    for(int i=1;i<=Q;i++) if(q[i].op==1) printf("%d
",q[i].ans);
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();Q=read();
    for(int i=1;i<=m;i++){
        e[i].u=read(),e[i].v=read(),e[i].w=read();
        if(e[i].u>e[i].v) swap(e[i].u,e[i].v);
    }
    sort(e+1,e+1+m);
    for(int i=1;i<=m;i++){//printf("e %d  %d %d %d
",i,e[i].u,e[i].v,e[i].w);
        e[i].id=i;
        val[n+i]=e[i].w;
        t[n+i].mxp=n+i;
    }
    sort(e+1,e+1+m,cmpuv);
    for(int i=1;i<=Q;i++){
        q[i].op=read(),q[i].x=read(),q[i].y=read();
        if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
        if(q[i].op==2){
            int k=e[bs(q[i].x,q[i].y)].id;
            del[k]=1;//printf("del %d
",k);
            q[i].del=k;
        }
    }
    solve();
}
 
 
 
 
 
原文地址:https://www.cnblogs.com/candy99/p/6278584.html