## 「学习笔记」网络战争 - KD-Tree - 最小割树 - 学习笔记

KDT本质上就是个做剪枝的过程，很好理解。

（这垃圾题写了将进7个k也真爽翻了的说

``````#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<vector>
#include<queue>
#include<assert.h>
#define mp make_pair
#define fir first
#define sec second
#define pb push_back
#define gc getchar()
#define INF (INT_MAX/2-10)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef pair<pii,int> piii;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int squ(int x) { return x*x; }
inline int gabs(int x) { return x<0?-x:x; }
const int N=50010;
int des[N],nc[N];vector<piii> es[N];
struct P{
static int cur_dim;int x[2],id,to;
P(int _x=0,int _y=0,int _id=0,int _to=0) { x[0]=_x,x[1]=_y,id=_id,to=_to; }
inline P operator=(const P &p) { return x[0]=p.x[0],x[1]=p.x[1],id=p.id,to=p.to,*this; }
inline int dis2(const P &p)const { return squ(x[0]-p.x[0])+squ(x[1]-p.x[1]); }
inline bool operator==(const P &p)const { return id==p.id; }
inline bool operator!=(const P &p)const { return id!=p.id; }
inline bool operator<(const P &p)const { return x[cur_dim]<p.x[cur_dim]; }
inline int input(int _i) { return scanf("%d%d",x,x+1),id=_i; }
inline int show()const { return cerr<<"("<<x[0]<<", "<<x[1]<<")"<<endl,0; }
}p[50010];
int P::cur_dim=0;
namespace KDT_space{
struct KDT_node{KDT_node *ch[2];P p;bool islf;int dim,pos;};
P nst;int bstd;
struct KDT{
KDT_node *rt;
inline int build(P *p,int n) { return build(rt,p,1,n,0); }
int build(KDT_node* &rt,P *p,int l,int r,int dim)
{
P::cur_dim=dim,rt=new KDT_node,rt->dim=dim,rt->islf=0;
if(l==r) return rt->p=p[l],rt->islf=1;int mid=(l+r)>>1;
nth_element(p+l,p+mid,p+r+1),rt->pos=p[mid].x[dim];
return build(rt->ch[0],p,l,mid,dim^1),build(rt->ch[1],p,mid+1,r,dim^1),0;
}
inline P find(const P &p) { return bstd=INF,find(rt,p),nst; }
int find(KDT_node* &rt,const P &p)
{
if(rt->islf)
{
int d;if(p==rt->p||(d=p.dis2(rt->p))>bstd) return 0;
if(d<bstd||nst.id>=rt->p.id) bstd=d,nst=rt->p;return 0;
}
int dim=rt->dim,pos=rt->pos,g=(p.x[dim]>pos);find(rt->ch[g],p);
if(squ(gabs(p.x[dim]-pos))<=bstd) find(rt->ch[g^1],p);return 0;
}
}kdt;
}
using KDT_space::kdt;
namespace BIGTREE_space{
const int N=50010,LOG=18;
vector<pii> to[N],g[N];int bel[N];
int d[N],up[N][LOG],mnv[N][LOG],Log[N];
struct BIGTREE{
int dfs(int x,int fa,int bl)
{
up[x][0]=fa,d[x]=d[fa]+1;
for(int i=1;i<=Log[d[x]];i++)
up[x][i]=up[up[x][i-1]][i-1],
mnv[x][i]=min(mnv[x][i-1],mnv[up[x][i-1]][i-1]);
for(int i=0,y;i<(int)g[x].size();i++)
if((y=g[x][i].fir)^fa) mnv[y][0]=g[x][i].sec,dfs(y,x,bl);
return bel[x]=bl;
}
inline int query(int x,int y)
{
if(bel[x]!=bel[y]) return 0;
if(d[x]<d[y]) swap(x,y);int ans=INF;
for(int i=Log[d[x]];i>=0;i--)
if(d[up[x][i]]>=d[y]) ans=min(ans,mnv[x][i]),x=up[x][i];
if(x==y) return ans;
for(int i=Log[d[x]];i>=0;i--) if(up[x][i]^up[y][i])
ans=min(ans,min(mnv[x][i],mnv[y][i])),x=up[x][i],y=up[y][i];
return min(ans,min(mnv[x][0],mnv[y][0]));
}
inline int build(P *p,int n)
{
for(int i=1,x,y;i<=n;i++)
x=p[i].id,y=p[i].to,to[x].pb(mp(y,des[x])),to[y].pb(mp(x,des[x]));
rep(x,1,n)
{
sort(to[x].begin(),to[x].end());
for(int i=0,j;i<(int)to[x].size();g[x].pb(mp(to[x][i].fir,to[x][i].sec)),i=j)
for(j=i+1;j<(int)to[x].size()&&to[x][i].fir==to[x][j].fir;to[x][i].sec+=to[x][j++].sec);
}
for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;i++) if(!bel[i]) dfs(i,0,i);
return 0;
}
}bigtree;
}
using BIGTREE_space::bigtree;
namespace MCT_space{
const int N=2010,M=4010,LOG=14;
queue<int> q;
struct edges{
int to,pre,resf,fsav;
}e[M];int h[N],cur[N],etop,lev[N],p[N],a[N];
inline int add_edge(int u,int v,int f)
{	int x=++etop;e[x].to=v,e[x].pre=h[u],h[u]=x;return e[x].resf=e[x].fsav=f,etop;	}
inline int bfs(int s,int t,int n)
{
memset(lev,0,sizeof(int)*(n+1));
while(!q.empty()) q.pop();
q.push(s),lev[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=h[x],y;i;i=e[i].pre)
if(!lev[y=e[i].to]&&e[i].resf)
q.push(y),lev[y]=lev[x]+1;
}
return lev[t]>0;
}
int dfs(int s,int t,int a)
{
if(s==t||!a) return a;int flow=0,f;
for(int &i=cur[s];i;i=e[i].pre)
if(lev[e[i].to]==lev[s]+1&&(f=dfs(e[i].to,t,min(a,e[i].resf)))>0)
{	e[i].resf-=f,e[((i-1)^1)+1].resf+=f,a-=f,flow+=f;if(!a) break;	}
return flow;
}
inline int dinic(int s,int t,int n)
{	int flow=0;while(bfs(s,t,n)) memcpy(cur,h,sizeof(int)*(n+1)),flow+=dfs(s,t,INF);return flow;	}
struct MCT{
int n;vector<int> Log,d;
vector<vector<int> > up,mnv;
vector<vector<pii> > g;
int getup(int x,int fa=0,int v=0)
{
up[x].resize(LOG+1),up[x][0]=fa,d[x]=d[fa]+1;
mnv[x].resize(LOG+1),mnv[x][0]=v;
for(int i=1;i<=Log[d[x]];i++)
up[x][i]=up[up[x][i-1]][i-1],
mnv[x][i]=min(mnv[x][i-1],mnv[up[x][i-1]][i-1]);
for(int i=0,y;i<(int)g[x].size();i++)
if((y=g[x][i].fir)^fa) getup(y,x,g[x][i].sec);
return 0;
}
inline int query(int x,int y)
{
if(d[x]<d[y]) swap(x,y);int ans=INF;
for(int i=Log[d[x]];i>=0;i--)
if(d[up[x][i]]>=d[y]) ans=min(ans,mnv[x][i]),x=up[x][i];
if(x==y) return ans;
for(int i=Log[d[x]];i>=0;i--)
if(up[x][i]^up[y][i]) ans=min(ans,min(mnv[x][i],mnv[y][i])),x=up[x][i],y=up[y][i];
return min(ans,min(mnv[x][0],mnv[y][0]));
}
inline int build(vector<piii> &es,int _nc)
{
n=_nc;memset(h,0,sizeof(int)*(n+1)),etop=0;
Rep(i,es) build_edge(es[i].fir.fir,es[i].fir.sec,es[i].sec);
g.resize(n+1),Log.resize(n+1),up.resize(n+1),mnv.resize(n+1);
rep(i,2,n) Log[i]=Log[i>>1]+1;d.resize(n+1);
rep(i,1,n) p[i]=i;build(1,n);getup(1);return 0;
}
int build(int l,int r)
{
if(l==r) return 0;int s=p[l],t=p[r];
rep(x,1,n) for(int i=h[x];i;i=e[i].pre) e[i].resf=e[i].fsav;
int w=dinic(s,t,n),L=l-1,R=r+1;g[s].pb(mp(t,w)),g[t].pb(mp(s,w));
rep(i,l,r) if(lev[p[i]]) a[++L]=p[i];else a[--R]=p[i];
memcpy(p+l,a+l,sizeof(int)*(r-l+1));return build(l,L),build(R,r);
}
}mct[50010];
}
using MCT_space::mct;
int main()
{
int n=inn(),u,v,m;
rep(i,1,n)
{
p[i].input(i),des[i]=inn(),nc[i]=inn(),m=inn();
while(m--) u=inn(),v=inn(),es[i].pb(mp(mp(u,v),inn()));
}
kdt.build(p,n);rep(i,1,n) p[i].to=kdt.find(p[i]).id;
bigtree.build(p,n);rep(i,1,n) mct[i].build(es[i],nc[i]);
for(int q=inn();q;q--)
{
int x=inn(),y=inn(),a=inn(),b=inn();
if(x==y) { printf("%d\n",mct[x].query(a,b));continue; }
int ans=bigtree.query(x,y);
ans=min(ans,mct[x].query(1,a));
ans=min(ans,mct[y].query(1,b));
printf("%d\n",ans);
}
return 0;
}
``````