码迷,mamicode.com
首页 > 其他好文 > 详细

网络战争

时间:2018-09-21 20:50:11      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:联通   shu   mil   集中   family   http   复杂   pac   clr   

PDF题面

技术分享图片

我曾经以为$LCT$已经足够毒瘤,直到我写了树套树。

我曾经又以为树套树已经足够毒瘤,直到我写了这道题。

$hhh$

这道题大概分为三个部分

 

一、首府之间最近点相连

由于$N$不超过$10^5$,且$|X_i|,|Y_i|$均匀随机,我们大可以使用$KD-Tree$,即先以每个州首府坐标建出$KD-Tree$,再枚举每一个点进行在$KD-Tree$中搜索,由于坐标随机,复杂度期望为$O(N\log n)$。

这里有一个性质,那就是一定不存在重边以外的简单环。因为如果存在,那么你一定能找到一个不符合要求的点,所以这样连出来的一定是树或森林。如果有重边,那么很显然若我们要割掉它,必须把两条边全部割掉,即把所有重边变成一条边,这条新的边权值是原来重边的和。并且在后续计算答案时,若两个点所在的州不在同一个连通块上,那么答案为$0$,因为本身就不联通,这个用并查集维护即可。

 

二、预处理最小割树

最小割树基于一个非常重要的理论:在$n$个点的无向图中,本质不同的割至多有$n-1$个。利用这个性质,我们可以将这个无向图重构成一棵树,每一条树边代表一种割的方案的代价。

具体的方法就是,设一开始所有的点都在同一个点集中,然后随便选一个点数大于$1$的点集$S$,从$S$中任取两点$a,b$,以$a,b$为源汇跑最小割,然后把$S$中和$a$在割集同一侧的点单独拿出来,$S$中剩下的点一定和$b$在割集的同一侧,这样产生了两个$S$的非空子集$S_1,S_2$,并且在重构的树上建立一条$(a,b)$权值为割集大小的树边,然后将$S_1,S_2$递归处理直到$|S|=1$为止,这样,任意两个点最小割就是在重构树上两个点的路径上最小的边权。虽然说这样的复杂度可能达到$O(Dinic\sum n_i^2)$这道题并没有其他更可行的做法......,不过在我写到这里的时候,隔壁的$julao$ Mys_C_K 走了过来告诉我这个复杂度是可以用均值不等式来证明在$Dinic$够快的情况下是合法的。

 

三、大小树跑倍增

大树就是每一个首府连成的树,小树就是每个州内部的最小割树,只是用倍增维护一下路径最小值而已,非常简单,没啥可说的。

 

来吧,面对疾风吧。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define mid ((l+r)>>1)
#define INF 1000000000
#define N 100200
#define HA main
using namespace std;
namespace IO{
    const int SS=(1<<20)+5;
    char buf[SS],*H,*K;
    inline char Get(){
        if(H==K) K=(H=buf)+fread(buf,1,SS,stdin);
        if(H==K) return -1;return *H++;
    }
    inline int read(){
        int x=0,fg=1;char c=Get();
        while(!isdigit(c)&&c!=‘-‘) c=Get();
        if(c==‘-‘) fg=-1,c=Get();
        while(isdigit(c)) x=x*10+c-‘0‘,c=Get();
        return x*fg;
    }
    char obuf[SS],*oS=obuf,*oT=oS+SS-1,c,qu[55];int qr;
    inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
    inline void putc(char x){*oS++ =x;if(oS==oT) flush();}
    void print(int x){
        if(!x) putc(‘0‘);
        if(x<0) putc(‘-‘),x=-x;
        while(x) qu[++qr]=x%10+‘0‘,x/=10;
        while(qr) putc(qu[qr--]);
        putc(‘\n‘);
    }
}
using namespace IO;
int sq(int x){return x*x;}
int n,m,fs[N],nt[N<<1],to[N<<1],len[N<<1],dt[N],ot[N],vis[N],kd;
int u[N<<6],v[N<<6],w[N<<6],V[N][2],E[N][2],tmp,now;
int res[N],G[N][18],P[N][18],D[N];
struct node{
    int id,c[2]; node(){}
    node(int _id,int _c0,int _c1){id=_id,c[0]=_c0,c[1]=_c1;}
    void gtin(int x){c[0]=read(),c[1]=read(),id=x;}
    bool operator <(const node&ot)const{return c[kd]<ot.c[kd];}
}p[N];
int dst(node x,node y){return sq(x.c[0]-y.c[0])+sq(x.c[1]-y.c[1]);}
struct TREE{
    int mi[N][2],mx[N][2],cnt,t[N],fa[N][18],F[N],W[N][18],L[N],R[N];
    int fst[N],nxt[N<<1],gto[N<<1],val[N],dis[N<<1],TMP,dep[N],Root;
    int fd(int x){return F[x]==x?x:F[x]=fd(F[x]);}
    void gt(int x,node k){mx[x][0]=mi[x][0]=k.c[0],mx[x][1]=mi[x][1]=k.c[1];}
    void iit(){cnt=TMP=0,memset(fst,-1,sizeof(fst)),memset(W,0x3f,sizeof(W));}
    int mind(int x,node k){
        if(!x) return INF; int tt=0;
        for(int i=0;i<2;i++){
            if(k.c[i]<mi[x][i]) tt+=sq(mi[x][i]-k.c[i]);
            else if(k.c[i]>mx[x][i]) tt+=sq(mx[x][i]-k.c[i]);
        }
        return tt;
    }
    void update(int x,int from){
        if(from==0) return;
        mx[x][0]=max(mx[x][0],mx[from][0]),mx[x][1]=max(mx[x][1],mx[from][1]);
        mi[x][0]=min(mi[x][0],mi[from][0]),mi[x][1]=min(mi[x][1],mi[from][1]);
    }
    void pushup(int x){gt(x,p[t[x]]),update(x,L[x]),update(x,R[x]);}
    void build(int &x,int l,int r,int nw){
        x=++cnt,L[x]=R[x]=0;
        m=nw,nth_element(p+l,p+mid,p+r+1);t[x]=mid,gt(x,p[t[x]]);
        if(l<mid) build(L[x],l,mid-1,nw^1),update(x,L[x]);
        if(mid<r) build(R[x],mid+1,r,nw^1),update(x,R[x]);
    }
    void query(int x,int ps){
        if(!x) return;
        if(t[x]!=ps){
            int t1=dst(p[ps],p[t[x]]);
            if(t1<dt[p[ps].id]) dt[p[ps].id]=t1,ot[p[ps].id]=p[t[x]].id;
            else if(t1==dt[p[ps].id]&&p[t[x]].id<ot[p[ps].id]) ot[p[ps].id]=p[t[x]].id;
        }
        int t1=mind(L[x],p[ps]),t2=mind(R[x],p[ps]);
        if(t1<t2){if(t1<=dt[p[ps].id]) query(L[x],ps);if(t2<=dt[p[ps].id]) query(R[x],ps);}
        else{if(t2<=dt[p[ps].id]) query(R[x],ps);if(t1<=dt[p[ps].id]) query(L[x],ps);}
    }
    void lk(int x,int y,int Len){nxt[TMP]=fst[x],fst[x]=TMP,gto[TMP]=y,dis[TMP++]=Len;}
    void DFS(int x,int last,int from){
        fa[x][0]=last,dep[x]=dep[last]+1,W[x][0]=from;
        for(int j=1;j<18;j++){
            fa[x][j]=fa[fa[x][j-1]][j-1];
            W[x][j]=min(W[x][j-1],W[fa[x][j-1]][j-1]);
        }
        for(int i=fst[x];i!=-1;i=nxt[i])
            if(gto[i]!=last) DFS(gto[i],x,dis[i]);
    }
    void cover(){
        for(int i=1;i<=n;i++) fst[i]=-1,F[i]=i,query(Root,i);
        for(int i=1;i<=n;i++){
            if(i==ot[ot[i]]&&val[ot[i]]>0) val[ot[i]]+=val[i],val[i]=0;
            else lk(i,ot[i],val[i]),lk(ot[i],i,val[i]),F[fd(i)]=fd(ot[i]);
        }
        for(int i=1;i<=n;i++) if(fd(i)==i) DFS(i,0,0); 
    }
    int minn(int x,int y){
        if(fd(x)!=fd(y)) return 0;
        if(dep[x]<dep[y]) swap(x,y); int now=INF;
        for(int j=17;j>=0;j--){
            if(dep[fa[x][j]]<dep[y]) continue;
            now=min(now,W[x][j]),x=fa[x][j];
        }
        for(int j=17;j>=0;j--){
            if(fa[x][j]==fa[y][j]) continue;
            now=min(now,min(W[x][j],W[y][j]));
            x=fa[x][j],y=fa[y][j];
        }
        while(x!=y) now=min(now,min(W[x][0],W[y][0])),x=fa[x][0],y=fa[y][0];
        return now;
    }
    void RUN(){build(Root,1,n,0);cover();}
}Cap;
struct Gomory_tree{
    int cur[N],S,T,rem[N],q[N],hd,tl,tt[N],pos[N],col[N],tot,sz,nw;
    void addedge(int x,int y,int rm){
        nt[tmp]=fs[x],fs[x]=tmp,to[tmp]=y,rem[tmp++]=rm;
        nt[tmp]=fs[y],fs[y]=tmp,to[tmp]=x,rem[tmp++]=rm;
    }
    void init(int B){
        tot=E[B][1]-E[B-1][1],sz=V[B][1]-V[B-1][1];
        for(int i=1;i<=sz;i++) fs[i]=-1,pos[i]=i; tmp=0,nw=E[B][0];
        for(int i=E[B][0];i<=E[B][1];i++) addedge(u[i],v[i],w[i]);
    }
    bool BFS(){
        for(int i=1;i<=sz;i++) cur[i]=fs[i],vis[i]=-2;
        hd=tl=0,vis[S]=1,q[tl++]=S;
        while(hd<tl){
            int x=q[hd++];
            for(int i=fs[x];i!=-1;i=nt[i]){
                if(rem[i]==0||vis[to[i]]>=0) continue;
                vis[to[i]]=vis[x]+1,q[tl++]=to[i];
            }
        }
        return vis[T]>0;
    }
    int dfs(int x,int mxf){
        if(x==T||!mxf) return mxf;
        int temp=0; 
        for(int &i=cur[x];i!=-1;i=nt[i]){
            if(rem[i]==0||vis[to[i]]!=vis[x]+1) continue;
            int lc=min(mxf-temp,rem[i]); int rc=dfs(to[i],lc);
            rem[i]-=rc,rem[i^1]+=rc,temp+=rc;
            if(temp==mxf) break;
        }   
        if(temp==0) vis[x]=-2;
        return temp;
    }
    int dinic(){int as=0;while(BFS()) as+=dfs(S,INF);return as;}
    void clr(){
        for(int i=0,sum;i<tmp;i+=2) sum=rem[i]+rem[i+1],rem[i]=rem[i+1]=(sum>>1);
        for(int i=1;i<=sz;i++) col[i]=0;
    }
    void Paint(int x){
        if(col[x]) return;
        col[x]=1;
        for(int i=fs[x];i!=-1;i=nt[i]) if(rem[i]) Paint(to[i]);
    }
    void solve(int l,int r){
        if(l==r) return; clr();
        S=pos[l],T=pos[r],w[nw]=dinic();
        int t1=l,t2=r; u[nw]=S,v[nw]=T,nw++;
        Paint(S);
        for(int i=l;i<=r;i++){
            if(col[pos[i]]) tt[t1++]=pos[i];
            else tt[t2--]=pos[i];
        }
        for(int i=l;i<=r;i++) pos[i]=tt[i];
        solve(l,t2),solve(t1,r);
    }
    void check(int x){init(x),solve(1,sz);}
}Cut;
void getdep(int x,int last,int from){
    res[x]=min(res[last],from);
    P[x][0]=last,G[x][0]=from,D[x]=D[last]+1;
    for(int j=1;j<18;j++){
        P[x][j]=P[P[x][j-1]][j-1];
        G[x][j]=min(G[x][j-1],G[P[x][j-1]][j-1]);
    }
    for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]!=last) getdep(to[i],x,len[i]);
}
int getans(int B1,int t1,int B2,int t2){
    if(Cap.fd(B1)!=Cap.fd(B2)) return 0;
    if(B1==B2){
        int fin=INF,x=t1+V[B1-1][1],y=t2+V[B1-1][1];
        if(D[x]<D[y]) swap(x,y);
        for(int j=17;j>=0;j--){
            if(D[P[x][j]]<D[y]) continue;
            fin=min(fin,G[x][j]),x=P[x][j];
        }
        for(int j=17;j>=0;j--){
            if(P[x][j]==P[y][j]) continue;
            fin=min(fin,min(G[x][j],G[y][j]));
            x=P[x][j],y=P[y][j];
        }
        if(x!=y) fin=min(fin,min(G[x][0],G[y][0]));
        return fin;
    }
    int fin=min(res[t1+V[B1-1][1]],res[t2+V[B2-1][1]]);
    return min(fin,Cap.minn(B1,B2));
}
int HA(){
    n=read(),memset(fs,-1,sizeof(fs));
    memset(dt,0x3f,sizeof(dt)),Cap.iit();
    for(int i=1;i<=n;i++){
        p[i].gtin(i),Cap.val[i]=read();
        V[i][0]=V[i][1]=V[i-1][1];E[i][0]=E[i][1]=E[i-1][1];
        V[i][0]++,E[i][0]++,V[i][1]+=read(),E[i][1]+=read(),res[V[i][0]]=INF;
        for(int j=E[i][0];j<=E[i][1];j++) u[j]=read(),v[j]=read(),w[j]=read();
    } Cap.RUN(),res[0]=INF;
    for(int i=1;i<=n;i++) Cut.check(i); memset(fs,-1,sizeof(fs)),tmp=0;
    for(int i=1;i<=n;i++){
        for(int j=E[i][0];j<E[i][0]+V[i][1]-V[i][0];j++){
            u[j]+=V[i-1][1],v[j]+=V[i-1][1];
            nt[tmp]=fs[u[j]],fs[u[j]]=tmp,to[tmp]=v[j],len[tmp++]=w[j];
            nt[tmp]=fs[v[j]],fs[v[j]]=tmp,to[tmp]=u[j],len[tmp++]=w[j];
        }
        getdep(V[i][0],0,INF);
    }
    for(int Q=read(),t1,t2,b1,b2,now;Q;Q--,tmp=0){
        b1=read(),b2=read(),t1=read(),t2=read();
        now=getans(b1,t1,b2,t2),print(now);
    }flush(); return 0;
}

 

网络战争

标签:联通   shu   mil   集中   family   http   复杂   pac   clr   

原文地址:https://www.cnblogs.com/OYJason/p/9688354.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!