题解:
好题!!
这题似乎能上我代码长度记录的前五?
调试时间长度应该也能上前五QAQ
首先题目要求的明显就是最小割,当然在整个森林上求Q次最小割肯定是会GG的,所以我们需要一个能快速求最小割的算法——最小割树。
最小割树,也叫分治最小割,就是通过预处理把原本的图缩成一颗树,树上两个节点路径上的最小边权就是它们的最小割,这个用树上倍增可以随便维护。
大概思想就是先求一次最小割,把划分出的S和T两个点集继续求最小割,向下分治然后连边缩点。
这题先对每个州预处理最小割树,州和州之间用KD树求出距离最近的点,然后查询的时候用树上倍增跳。
分别写出来就好了qwq
所以这就是道码农题,码码码码码码
有必要说一下时间复杂度是O(玄学),这个时间复杂度严格来说是过不了的,但是数据随机,每个州和大的森林联通块的期望大小不大,所以不知道为什么就过了。。。
PS:我没写KD树,写了个排序剪枝,也是玄学就过了。。。
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #include<map>
8 #define inf 2147483647
9 #define eps 1e-9
10 using namespace std;
11 typedef long long ll;
12 struct node{
13 int x,y,id;
14 friend bool operator <(node a,node b){
15 if(a.x!=b.x)return a.x<b.x;
16 if(a.y!=b.y)return a.y<b.y;
17 return a.id<b.id;
18 }
19 }p[300001],pp[300001];
20 int N,n,m,q,u,v,w,ta,tb,qa,qb,cnt=0,bcc=0,num[300001],fr[300001],pts[300001],blg[300001];
21 bool used[300001];
22 namespace capitals{
23 struct edge{
24 int v,w,next;
25 }a[300001];
26 int tot=0,head[300001],dep[300001],fa[300001][20],minn[300001][20];
27 void add(int u,int v,int w){
28 a[++tot].v=v;
29 a[tot].w=w;
30 a[tot].next=head[u];
31 head[u]=tot;
32 }
33 void dfs(int u,int ff,int dpt,int d){
34 blg[u]=bcc;
35 dep[u]=dpt;
36 fa[u][0]=ff;
37 minn[u][0]=d;
38 for(int i=1;i<=19;i++){
39 fa[u][i]=fa[fa[u][i-1]][i-1];
40 minn[u][i]=min(minn[u][i-1],minn[fa[u][i-1]][i-1]);
41 }
42 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
43 int v=a[tmp].v;
44 if(v!=ff){
45 dfs(v,u,dpt+1,a[tmp].w);
46 }
47 }
48 }
49 int query(int u,int v){
50 if(dep[u]<dep[v])swap(u,v);
51 int ret=inf;
52 for(int i=19;i>=0;i--){
53 if(dep[fa[u][i]]>=dep[v]){
54 ret=min(ret,minn[u][i]);
55 u=fa[u][i];
56 }
57 }
58 if(u==v)return ret;
59 for(int i=19;i>=0;i--){
60 if(fa[u][i]!=fa[v][i]){
61 ret=min(ret,min(minn[u][i],minn[v][i]));
62 u=fa[u][i],v=fa[v][i];
63 }
64 }
65 return min(ret,min(minn[u][0],minn[v][0]));
66 }
67 }
68 namespace dinic{
69 struct edge{
70 int v,w,next;
71 }a[300001];
72 int n,m,vs,vt,tot=0,dep[300001],s[300001],flw[300001],nmd[300001],head[300001];
73 queue<int>q;
74 void add(int u,int v,int w){
75 a[++tot].v=v;
76 a[tot].w=w;
77 a[tot].next=head[u];
78 head[u]=tot;
79 }
80 void clr(){
81 //memset(head,-1,sizeof(head));
82 for(int i=1;i<=n;i++)head[i]=-1;
83 tot=1;
84 }
85 bool bfs(){
86 for(int i=1;i<=n;i++)dep[i]=0;
87 while(!q.empty())q.pop();
88 q.push(vs);
89 dep[vs]=1;
90 while(!q.empty()){
91 int u=q.front();
92 q.pop();
93 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
94 int v=a[tmp].v;
95 if(!dep[v]&&a[tmp].w){
96 dep[v]=dep[u]+1;
97 if(v==vt)return true;
98 q.push(v);
99 }
100 }
101 }
102 return false;
103 }
104 int dfs(int u,int num){
105 if(u==vt||!num)return num;
106 int ans=0;
107 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
108 int v=a[tmp].v;
109 if(dep[v]==dep[u]+1&&a[tmp].w){
110 int f=dfs(v,min(num,a[tmp].w));
111 if(f){
112 a[tmp].w-=f;
113 a[tmp^1].w+=f;
114 ans+=f;
115 num-=f;
116 if(!num)break;
117 }
118 }
119 }
120 if(!ans)dep[u]=-1;
121 return ans;
122 }
123 void build_mincost(int l,int r){
124 if(r<=l)return;
125 int dnc=0,ls=l,rs=r;
126 vs=nmd[l],vt=nmd[r];
127 for(int i=2;i<=tot+1;i++)a[i].w=flw[i/2];
128 while(bfs())dnc+=dfs(vs,inf);
129 for(int i=l;i<=r;i++){
130 if(dep[nmd[i]])s[ls++]=nmd[i];
131 else s[rs--]=nmd[i];
132 }
133 for(int i=l;i<=r;i++)nmd[i]=s[i];
134 capitals::add(vs+cnt,vt+cnt,dnc);
135 capitals::add(vt+cnt,vs+cnt,dnc);
136 //printf("Added %d->%d Flow=%d
",vs+cnt,vt+cnt,dnc);
137 build_mincost(l,ls-1);
138 build_mincost(rs+1,r);
139 }
140 }
141 int dis(node a,node b){
142 return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
143 }
144 void solve(int k){
145 int ans=inf,now=0;
146 for(int i=k+1;i<=N;i++){
147 if((pp[i].x-pp[k].x)*(pp[i].x-pp[k].x)>ans)break;
148 int ds=dis(pp[i],pp[k]);
149 if(ds<ans){
150 ans=ds;
151 now=i;
152 }else if(ds==ans&&pp[i].id<pp[now].id)now=i;
153 }
154 for(int i=k-1;i;i--){
155 if((pp[i].x-pp[k].x)*(pp[i].x-pp[k].x)>ans)break;
156 int ds=dis(pp[i],pp[k]);
157 if(ds<ans){
158 ans=ds;
159 now=i;
160 }else if(ds==ans&&pp[i].id<pp[now].id)now=i;;
161 }
162 fr[pp[k].id]=pp[now].id;
163 }
164 int main(){
165 memset(capitals::head,-1,sizeof(capitals::head));
166 scanf("%d",&N);
167 for(int i=1;i<=N;i++){
168 scanf("%d%d%d%d%d",&p[i].x,&p[i].y,&num[i],&n,&m);
169 p[i].id=i;
170 pp[i]=p[i];
171 pts[i]=cnt+1;
172 dinic::n=n;
173 dinic::m=m;
174 dinic::clr();
175 for(int j=1;j<=n;j++)dinic::nmd[j]=j;
176 for(int j=1;j<=m;j++){
177 scanf("%d%d%d",&u,&v,&w);
178 dinic::add(u,v,w);
179 dinic::add(v,u,w);
180 dinic::flw[j]=w;
181 }
182 dinic::build_mincost(1,n);
183 cnt+=n;
184 }
185 sort(pp+1,pp+N+1);
186 for(int i=1;i<=N;i++)solve(i);
187 for(int i=1;i<=N;i++){
188 if(used[i])continue;
189 if(i==fr[fr[i]]){
190 used[fr[i]]=true;
191 capitals::add(pts[i],pts[fr[i]],num[i]+num[fr[i]]);
192 capitals::add(pts[fr[i]],pts[i],num[i]+num[fr[i]]);
193 //printf("Added %d->%d Flow=%d
",pts[fr[i]],pts[i],num[i]+num[fr[i]]);
194 }else{
195 capitals::add(pts[i],pts[fr[i]],num[i]);
196 capitals::add(pts[fr[i]],pts[i],num[i]);
197 //printf("Added %d->%d Flow=%d
",pts[fr[i]],pts[i],num[i]);
198 }
199 }
200 for(int i=1;i<=N;i++){
201 if(!blg[pts[i]]){
202 bcc++;
203 capitals::dfs(pts[i],0,1,inf);
204 }
205 }
206 scanf("%d",&q);
207 for(int i=1;i<=q;i++){
208 scanf("%d%d%d%d",&ta,&tb,&qa,&qb);
209 qa=pts[ta]+qa-1;
210 qb=pts[tb]+qb-1;
211 if(blg[qa]!=blg[qb])puts("0");
212 else printf("%d
",capitals::query(qa,qb));
213 }
214 return 0;
215 }