BZOJ4388 : JOI2012 invitation
注意到这个过程实质就是prim算法求最大生成树的过程。
首先通过离散化+线段树将$A+B$个点缩为上下各$O(n)$个点。
设已加入集合为$S$,未加入集合为$T$。
建立两棵线段树,维护所有在$T$集合中的点,以及从每个点连出去的边。
用一个大根堆维护所有横跨$ST$的边。每次取出堆顶的边,取出与这条边相连的任意一个属于$T$集合的点,若取不出则将这条边删去;否则将这个点加入$S$,并将所有连了它的边加入堆中。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<iostream> #include<cstdlib> #include<queue> #include<algorithm> using namespace std; typedef long long ll; typedef pair<int,int>P; const int N=100010,M=200010,T=525000,L=2000000; int C,n,i,x,y,seq[M];ll ans;bool del[N]; struct E{int a,b,c,d,t;}e[N]; priority_queue<P>Q; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} void NO(){ puts("-1"); exit(0); } inline void umax(int&a,int b){if(a<b)a=b;} struct World{ int n,m,b[N<<1]; int val[T],g[T],v[L],nxt[L],ed; inline int lower(int x){ int l=1,r=m,mid,t; while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1; return t; } inline void addx(int x,int y){b[++m]=x;b[++m]=y;} void pre(){ b[++m]=1,b[++m]=n; sort(b+1,b+m+1); int _m=m; m=0; for(int i=1;i<=_m;i++)if(b[i]!=b[i-1])b[++m]=b[i]; } inline void find(int&x,int&y){x=lower(x),y=lower(y);} void cal(){ for(int i=1;i<m;i++)if(b[i+1]-b[i]-1){ if(!seq[i])NO(); ans+=1LL*seq[i]*(b[i+1]-b[i]-1); } } void build(int x,int a,int b){ val[x]=b; if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } void ins(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){ v[++ed]=p;nxt[ed]=g[x];g[x]=ed; return; } int mid=(a+b)>>1; if(c<=mid)ins(x<<1,a,mid,c,d,p); if(d>mid)ins(x<<1|1,mid+1,b,c,d,p); } int ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return val[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(x<<1,a,mid,c,d); if(d>mid)umax(t,ask(x<<1|1,mid+1,b,c,d)); return t; } void change(int x,int a,int b,int c){ for(int&i=g[x];i;i=nxt[i]){ int j=v[i]; if(!del[j])Q.push(P(e[j].t,j)),del[j]=1; } if(a==b){val[x]=0;return;} int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c);else change(x<<1|1,mid+1,b,c); val[x]=max(val[x<<1],val[x<<1|1]); } }A,B; int v[T]; void build(int x,int a,int b){ v[x]=0; if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } void change(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){umax(v[x],p);return;} int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c,d,p); if(d>mid)change(x<<1|1,mid+1,b,c,d,p); } void dfs(int x,int a,int b){ if(a==b){seq[a]=v[x];return;} int mid=(a+b)>>1; umax(v[x<<1],v[x]),umax(v[x<<1|1],v[x]); dfs(x<<1,a,mid),dfs(x<<1|1,mid+1,b); } int main(){ read(A.n),read(B.n),read(C),read(n); for(i=1;i<=n;i++){ read(e[i].a),read(e[i].b),read(e[i].c),read(e[i].d),read(e[i].t); A.addx(e[i].a,e[i].b); B.addx(e[i].c,e[i].d); } A.pre(); for(i=1;i<=n;i++)A.find(e[i].a,e[i].b); build(1,1,A.m); for(i=1;i<=n;i++)if(e[i].a<e[i].b)change(1,1,A.m,e[i].a,e[i].b-1,e[i].t); dfs(1,1,A.m); A.cal(); B.pre(); for(i=1;i<=n;i++)B.find(e[i].c,e[i].d); build(1,1,B.m); for(i=1;i<=n;i++)if(e[i].c<e[i].d)change(1,1,B.m,e[i].c,e[i].d-1,e[i].t); dfs(1,1,B.m); B.cal(); A.build(1,1,A.m); B.build(1,1,B.m); for(i=1;i<=n;i++){ A.ins(1,1,A.m,e[i].a,e[i].b,i); B.ins(1,1,B.m,e[i].c,e[i].d,i); } A.change(1,1,A.m,1); while(!Q.empty()){ x=Q.top().second;Q.pop(); if(y=A.ask(1,1,A.m,e[x].a,e[x].b)){ ans+=e[x].t; A.change(1,1,A.m,y); Q.push(P(e[x].t,x)); continue; } if(y=B.ask(1,1,B.m,e[x].c,e[x].d)){ ans+=e[x].t; B.change(1,1,B.m,y); Q.push(P(e[x].t,x)); continue; } } if(A.val[1]||B.val[1])NO(); return printf("%lld",ans),0; }