太久没做网络流的 思维题了,智力急速下降。。。
这个题很妙
主要分析建图想法
注意,多条边的交叉情况也是基于这两种的。发现它具有网络流的性质吧?所以考虑它怎么和网络流联系在一起。把初始点权为1的看做S集合,点权为0的看做T集合。我们其实要做的就是处理完S到T的所有边,使代价最小。把代价当做割开一条路径的花费,所求问题即为割最少的边使得S到T不连通。
主要思想就是 :: 划分集合 + 隔绝集合
很显然对于一个点来说,任意有两个点权值不同的
显然就要给这个点赋权来断开
那么对于多叉的同理
对于一段连续的无权值的
可以缩成一起
就这样就解决了
最小割在这里起到的分离集合的作用
瓶颈是想到将点权不同的点划分入相应集合,并且在原图上将其分离
还是比较妙的。。。
#include<bits/stdc++.h>
#define MAXN 7005
typedef long long ll;
using namespace std;
int n,m,h[MAXN],tot,k,s,t;
ll p[MAXN],ans,zz;
int dep[MAXN],vis[MAXN],cur[MAXN],gg;
struct node{
int from,to,next;
ll rest;
}e[MAXN << 1] , e2[MAXN << 1];
void add(int x , int y , ll z){
tot++;
e[tot].from = x;
e[tot].to = y;
e[tot].rest = z;
e[tot].next = h[x];
h[x] = tot;
}
void init(){
tot = (-1);
memset(p , -1 , sizeof(p));
memset(h , -1 , sizeof(h));
cin>>n>>m;
for(int i = 1 ; i <= m ; i++)cin>>e2[i].from>>e2[i].to;
cin>>k;ll x,y;
for(int i = 1 ; i <= k ; i++){
cin>>x>>y;
p[x] = y;
}
}
int bfs(){
memset(dep , 0x3f , sizeof(dep));
memset(vis , 0 , sizeof(vis));
int now;queue<int>q;q.push(s);
vis[s] = dep[s] = 1;
while(!q.empty()){
now = q.front() , q.pop();vis[now] = 0;
for(int i = h[now] ; i != (-1) ; i = e[i].next){
if(!e[i].rest || dep[e[i].to] <= dep[now] + 1)continue;
dep[e[i].to] = dep[now] + 1;
if(!vis[e[i].to])vis[e[i].to] = 1 , q.push(e[i].to);
}
}
if(dep[t] == 0x3f3f3f3f)return 0;
return 1;
}
ll dfs(int now , ll low){
if(now == t){
ans += low;
gg = 1;
return low;
}
ll used = low , res;
for(int i = h[now] ; i != (-1) ; i = e[i].next){
if(!e[i].rest || dep[e[i].to] != dep[now] + 1)continue;
if(res = dfs(e[i].to , min(used , e[i].rest))){
used -= res;
e[i].rest -= res;
e[i ^ 1].rest += res;
if(!used)break;
}
}
return low - used;
}
void dinic(){
while(bfs()){
gg = 1;
while(gg){
gg = 0;
dfs(s , 0x3f3f3f3f);
}
}
}
void solve(){
s = zz = ans = 0 , t = n + 1;
for(ll cishu = 30 ; cishu >= 0 ; cishu--){
memset(h , -1 , sizeof(h));tot = (-1);
for(int i = 1 ; i <= n ; i++){
if(p[i] == (-1))continue;
if((p[i] >> cishu) & 1)add(i , t , 0x3f3f3f3f) , add(t , i , 0);
else add(s , i , 0x3f3f3f3f) , add(i , s , 0);
}
for(int i = 1 ; i <= m ; i++){
add(e2[i].from , e2[i].to , 1);
add(e2[i].to , e2[i].from , 1);
}
ans = 0;
dinic();
zz += (1 << cishu) * ans;
}
cout<<zz<<endl;
}
int main(){
init();
solve();
}