[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]
Description
A 联邦国有 N 个州,每个州内部都有一个网络系统,有若干条网络线路,连接各个 州内部的城市。 由于 A 国的州与州之间的关系不是太好,每个州都只有首府建立了到别的州的网络。具体来说,每个州的首府都只主动地建立了一条网络线路,连接到距离最近的州的 首府。(欧氏距离。如果有多个,选择标号最小的去连接) B 国探知了 A 国的网络线路分布情况,以及攻陷每条网络线路所需花费的代价,B 国首脑想知道断开 A 国某两个城市之间的网络连接,所需的最少代价。请你计算出来告 诉他。 注:两个城市之间可以有多条网络线路。可能有两个首府的坐标相同。
【输入格式】
第一行有一个正整数 N,表示 A 国州的个数。
接下来 N 个部分,每个部分描述每个州的情况: 第一行两个整数𝑥𝑖,𝑦𝑖,表示第 i 个州的首府坐标。
第二行一个正整数𝑣𝑖,表示攻陷这个州主动建立的网络线路的代价。
第三行两个正整数𝑛𝑖,𝑚𝑖,表示第 i 个州有𝑛𝑖个城市,𝑚𝑖条网络线路。
接下来𝑚𝑖行,每行三个数𝑎𝑖,𝑏𝑖,𝑐𝑖,表示第 i 个州中城市𝑎𝑖和𝑏𝑖之间有一条网络线路,攻陷它的代价为𝑐𝑖。
编号为 1 的城市,是这个州的首府。
接下来一行一个正整数 Q,表示询问个数。
接下来 Q 行,每行四个数 ta,tb,qa,qb,表示询问断开第 ta 个州第 qa 个城市和 第 tb 个州第 qb 个城市的最小代价。
【输出格式】 输出 Q 行,每行一个数,表示一组询问的答案
Solution
码农题啊啊啊啊啊
先用kd-tree求出每个首府向外连接的的点。可以证明不会出现>=3个节点的环。证明如下:
假如有一个3个节点的环a->b->c->a。(这里画成有向边的意思是为了清晰表示哪条边是哪个首府主动建的)
由于a->b,则dis(a,b)<=dis(a,c)。
同理dis(c,a)<=dis(b,c)<=dis(a,b)<=dis(a,c)。
所以dis(a,b)=dis(a,c)=dis(b,c)。
然后我们就会发现,不论怎么给a,b,c编号,都无法满足要求了。
接下来,直接用最小割树求出最小割,每次查询在树上倍增。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<map> using namespace std; const int inf=1e9; int n,st[50010]; struct pas{int y,nxt,w,op;}; struct Gomory_Hu { pas g[300010];int tot,h[100010]; int fa[100010][18],mn[100010][18],dep[100010]; void add(int x,int y,int w) {g[++tot]=pas{y,h[x],w,0};h[x]=tot; g[++tot]=pas{x,h[y],w,0};h[y]=tot;} void pre(int x,int f,int c) { fa[x][0]=f;mn[x][0]=c;dep[x]=dep[f]+1; for (int i=1;i<=16;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; mn[x][i]=min(mn[x][i-1],mn[fa[x][i-1]][i-1]); } for (int i=h[x];i;i=g[i].nxt) if (g[i].y!=f)pre(g[i].y,x,g[i].w); } int asklca(int x,int y) { int ret=inf; if (dep[x]<dep[y]) swap(x,y); for (int i=17;i>=0;i--) if (dep[fa[x][i]]>dep[y]) ret=min(ret,mn[x][i]),x=fa[x][i]; if (dep[x]>dep[y]) ret=min(ret,mn[x][0]),x=fa[x][0]; if (x==y) return ret; for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) ret=min(ret,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i]; ret=min(ret,min(mn[x][0],mn[y][0])); return ret; } }gh; struct Dinic { pas g[8000010]; int h[100010],tot=0,S,T; int reid[8000010],reflow[8000010],pos; int dep[100010]; queue<int>q; bool bfs(int _i) { int x; memset(dep+st[_i],0,sizeof(int)*(st[_i+1]-st[_i]+1));dep[S]=1; while (!q.empty()) q.pop(); q.push(S); while (!q.empty()) { x=q.front();q.pop(); for (int i=h[x];i;i=g[i].nxt) if (!dep[g[i].y]&&g[i].w) { dep[g[i].y]=dep[x]+1; q.push(g[i].y); if (g[i].y==T) return 1; } } return 0; } int dfs(int x,int flow) { if (x==T||(!flow))return flow; int tmp=0,js; for (int i=h[x];i;i=g[i].nxt) if (dep[g[i].y]==dep[x]+1&&g[i].w) { js=dfs(g[i].y,min(flow,g[i].w)); if (js) { g[i].w-=js; g[g[i].op].w+=js; tmp+=js; flow-=js; reid[++pos]=i;reflow[pos]=js; if (!flow) return tmp; } } if (flow) dep[x]=-1; return tmp; } void add(int x,int y,int w)//无向图! { g[++tot]=pas{y,h[x],w,tot+1};h[x]=tot; g[++tot]=pas{x,h[y],w,tot-1};h[y]=tot; } int _in[100010],_flow[100010]; void get_gh(int _i,int l,int r) { for (int i=l;i<=r;i++) _in[i]=l; for (int i=l+1;i<=r;i++) { S=i;T=_in[i]; while (bfs(_i)) _flow[i]+=dfs(S,inf); for (int j=i+1;j<=r;j++) if (_in[i]==_in[j]&&dep[j]) _in[j]=i; while (pos) { g[reid[pos]].w+=reflow[pos]; g[g[reid[pos]].op].w-=reflow[pos];pos--; } } for (int i=l+1;i<=r;i++) gh.add(i,_in[i],_flow[i]),_flow[i]=0; } }D; int v[50010]; map<int,int>mp[50010]; int rt,nw; struct node{int t[2],id; friend bool operator<(node a,node b){return a.t[nw]<b.t[nw];} }p[100010],_p[100010]; struct KD_TREE { int up[100010],down[100010],lft[100010],rght[100010]; int lc[100010],rc[100010],cnt=0; void pushup(int k) { if (lc[k]) { up[k]=max(up[k],up[lc[k]]); down[k]=min(down[k],down[lc[k]]); lft[k]=min(lft[k],lft[lc[k]]); rght[k]=max(rght[k],rght[lc[k]]); } if (rc[k]) { up[k]=max(up[k],up[rc[k]]); down[k]=min(down[k],down[rc[k]]); lft[k]=min(lft[k],lft[rc[k]]); rght[k]=max(rght[k],rght[rc[k]]); } } int build(int _now,int l,int r) { if (l>r) return 0; int mid=(l+r)/2;nw=_now; nth_element(p+l,p+mid+1,p+r+1); up[mid]=down[mid]=p[mid].t[1]; lft[mid]=rght[mid]=p[mid].t[0]; lc[mid]=build(_now^1,l,mid-1); rc[mid]=build(_now^1,mid+1,r); pushup(mid); return mid; } int dis(node a,node b) {return (a.t[0]-b.t[0])*(a.t[0]-b.t[0])+(a.t[1]-b.t[1])*(a.t[1]-b.t[1]);} int _get(int k,node q) { int ret=0; if (q.t[0]<lft[k]) ret+=(q.t[0]-lft[k])*(q.t[0]-lft[k]); if (q.t[0]>rght[k]) ret+=(q.t[0]-rght[k])*(q.t[0]-rght[k]); if (q.t[1]<down[k]) ret+=(q.t[1]-down[k])*(q.t[1]-down[k]); if (q.t[1]>up[k]) ret+=(q.t[1]-up[k])*(q.t[1]-up[k]); return ret; } int ans,qid; void query(int k,int q) { if (!k) return; if (p[k].id!=q) { int re=dis(p[k],_p[q]); if (ans>re) qid=p[k].id,ans=re; else if (ans==re) qid=min(qid,p[k].id); } int ll=_get(lc[k],_p[q]),rr=_get(rc[k],_p[q]); if (ll<=rr) { if (ll<=ans) query(lc[k],q); if (rr<=ans) query(rc[k],q); } else { if (rr<=ans) query(rc[k],q); if (ll<=ans) query(lc[k],q); } } void solve() { int c; for (int i=1;i<=n;i++) _p[i]=p[i]; rt=build(0,1,n); for (int i=1;i<=n;i++) { ans=inf;qid=0; query(rt,i); c=i; if (c>qid) swap(c,qid); mp[c][qid]+=v[i]; } map<int,int>::iterator it; for (int i=1;i<=n;i++) for (it=mp[i].begin();it!=mp[i].end();it++) gh.add(st[i],st[it->first],it->second); } }kd; int _n,_m,x,y,z; int Q,ta,tb,qa,qb; int main() { scanf("%d",&n); st[1]=1; for (int i=1;i<=n;i++) { scanf("%d%d",&p[i].t[0],&p[i].t[1]); p[i].id=i; scanf("%d%d%d",&v[i],&_n,&_m); st[i+1]=st[i]+_n; for (int j=1;j<=_m;j++) { scanf("%d%d%d",&x,&y,&z); D.add(st[i]+x-1,st[i]+y-1,z); } } kd.solve(); for (int i=1;i<=n;i++) D.get_gh(i,st[i],st[i+1]-1); for (int i=1;i<=st[n+1]-1;i++) if (!gh.fa[i][0]) gh.pre(i,i,0); scanf("%d",&Q); while (Q--) { scanf("%d%d%d%d",&ta,&tb,&qa,&qb); x=st[ta]+qa-1;y=st[tb]+qb-1; printf("%d\n",gh.asklca(x,y)); } }