您的位置:首页 > 其它

BZOJ3712 [PA2014]Fiolki

2017-03-29 10:52 295 查看
容易发现我们只需要求出每种反应的发生时间,然后排序做一遍即可

求反应的发生时间,就相当于一张图,开始每个点都是单独一个连通块,连通块会不断合并,求每条边的两个端点联通的时间

整体二分一下即可,每次判断现在是否联通吧边分到左右两边

用dfs版的话并查集回滚要按秩合并,多个log,所以写bfs版的就好

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 500010
#define MAXM 200010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
struct data{
int x;
int y;
int X;
int Y;
data(){

}
data(int _x,int _y,int _X=0,int _Y=0){
x=_x;
y=_y;
X=_X;
Y=_Y;
}
};
data q[MAXN];
int hd,tl;
data th[MAXN];
int n,m,H;
int a[MAXN];
data e[MAXN];
data h[MAXN];
int f[MAXN];
ll ans;
int fa(int x){
return f[x]==x?x:f[x]=fa(f[x]);
}
int main(){
int i;
scanf("%d%d%d",&n,&m,&H);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(i=1;i<=m;i++){
scanf("%d%d",&e[i].x,&e[i].y);
}
for(i=1;i<=H;i++){
scanf("%d%d",&h[i].x,&h[i].y);
h[i].Y=i;
}
q[(tl%=MAXN)++]=data(1,m,1,H);
int wzh=m+1;
while(hd!=tl){
data x=q[(hd%=MAXN)++];
int l=x.x,r=x.y,L=x.X,R=x.Y;
int mid=l+r>>1;
if(wzh>mid){
for(i=1;i<=n;i++){
f[i]=i;
}
wzh=1;
}
while(wzh<=mid){
f[fa(e[wzh].x)]=fa(e[wzh].y);
wzh++;
}
int tl=L-1,tr=R+1;
for(i=L;i<=R;i++){
if(fa(h[i].x)==fa(h[i].y)){
th[++tl]=h[i];
}
}
for(i=R;i>=L;i--){
if(fa(h[i].x)!=fa(h[i].y)){
th[--tr]=h[i];
}
}
memcpy(h+L,th+L,sizeof(data)*(R-L+1));
if(l!=r){
if(tl>=L){
q[(::tl%=MAXN)++]=data(l,mid,L,tl);
}
if(tl<R){
q[(::tl%=MAXN)++]=data(mid+1,r,tl+1,R);
}
}
}
for(i=1;i<=n;i++){
f[i]=i;
}
for(i=1;i<=m;i++){
f[fa(e[i].x)]=fa(e[i].y);
}
for(i=1;i<=H;i++){
if(fa(h[i].x)==fa(h[i].y)){
int t=min(a[h[i].x],a[h[i].y]);
ans+=t*2;
a[h[i].x]-=t;
a[h[i].y]-=t;
}
}
printf("%lld\n",ans);
return 0;
}

/*
4 3 2
27 46 75 69
4 2
3 2
2 1
1 3
3 4

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: