[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]

Posted coco-night

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
",gh.asklca(x,y));
    }
}

 

以上是关于[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]的主要内容,如果未能解决你的问题,请参考以下文章

[XSY 1145] 网络战争 平面最近点对 最小割树

网络战争 [KD-Tree+最小割树]

[2016北京集训试题6]mushroom-[bitset]

[2016北京集训试题6]魔法游戏-[博弈论-sg函数]

[2016北京集训试题17]数组-[线段树]

[2016北京集训试题15]cot-[分块]