您的位置:首页 > 其它

NOIP模拟 图【最小生成树】

2017-11-07 20:50 260 查看

题目大意:

给n个点,m1条A边,m2条B边,A,B边所构成的图都是联通的;

有q次询问,每次询问给出x,问将所有A边加上x,B边减去x后图中的最小生成树是多少。1<=n,q<=1000;

解题思路:

注意到当x为负无穷时答案就是A边构成的MST,为正无穷时就是B边构成的MST,所以当x逐渐增大,B边构成的MST上的边就会逐渐取代A边构成的MST上的边。而最优的肯定是小的B边先加进去取代路径上最大的A边。

所以我们可以按B边从小到大的顺序算出加进每条B边时的x的下界,同时不断修改树的形态即可。而且这样如果两条B边影响的路径有交集,其x的下界是递增的,而如果没有交集,x虽不是递增的,但不影响另一条边所替换的A边,可是会影响当前MST的大小。所以最后才能把替换操作按x从小到大排序后计算当前x下MST的大小。

然后把询问也按x从小到大排序后计算当前x下MST的大小即可。

由于修改树的形态是O(n)的(LCT可优化到O(logn)),所以做复杂度为O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

const int N=100005,M=200005,INF=0x3f3f3f3f;
int n,m1,m2,Q;
int fa
,len
,stk
,visit
;
int tot,first
,nxt[M],to[M],w[M];
ll totlen,ans
;
bool exist[M];
struct edge
{
int x,y
14561
,w;
friend inline bool operator <(const edge &a,const edge &b)
{return a.w<b.w;}
}bian1[M],bian2[M];
struct node
{
int x,w1,w2;ll val;
friend inline bool operator <(const node &a,const node &b)
{return a.x<b.x;}
}upt[M];
struct node1
{
int x,id;
friend inline bool operator <(const node1 &a,const node1 &b)
{return a.x<b.x;}
}q
;

int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}

void add(int x,int y,int z)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}

void kruskal1()
{
for(int i=1;i<=n;i++)fa[i]=i;
sort(bian1+1,bian1+m1+1);
int k=0;
for(int i=1;i<=m1;i++)
{
int x=find(bian1[i].x),y=find(bian1[i].y);
if(x!=y)
{
k++;totlen+=bian1[i].w;
add(bian1[i].x,bian1[i].y,bian1[i].w);
add(bian1[i].y,bian1[i].x,bian1[i].w);
fa[y]=x;
}
if(k==n-1)break;
}
}

void kruskal2()
{
for(int i=1;i<=n;i++)fa[i]=i;
sort(bian2+1,bian2+m2+1);
int k=0;
for(int i=1;i<=m2;i++)
{
int x=find(bian2[i].x),y=find(bian2[i].y);
if(x!=y)k++,exist[i]=true,fa[y]=x;
if(k==n-1)break;
}
int cnt=0;
for(int i=1;i<=m2;i++)
if(exist[i])bian2[++cnt]=bian2[i];
m2=cnt;
memset(fa,0,sizeof(fa));
}

void dfs(int u)
{
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];
if(v==fa[u])continue;
fa[v]=u;len[v]=w[e];
dfs(v);
}
}

void solve(int i)
{
int x=bian2[i].x,y=bian2[i].y,mx=-INF,pos,top,bz=2;
visit[x]=i;
while(fa[x])visit[fa[x]]=i,x=fa[x];
while(visit[y]!=i)
{
if(len[y]>mx)mx=len[y],pos=y,bz=2;
y=fa[y];
}
x=bian2[i].x;
while(x!=y)
{
if(len[x]>mx)mx=len[x],pos=x,bz=1;
x=fa[x];
}
upt[i].w1=mx,upt[i].w2=bian2[i].w,upt[i].x=(bian2[i].w-mx+1)/2;
x=bian2[i].x,y=bian2[i].y,top=0;
if(bz==2)swap(x,y);
while(x!=fa[pos])stk[++top]=x,x=fa[x];
for(int j=top;j>1;j--)fa[stk[j]]=stk[j-1],len[stk[j]]=len[stk[j-1]];
x=stk[1],fa[x]=y,len[x]=-INF;
}

int main()
{
//freopen("mst.in","r",stdin);
//freopen("mst.out","w",stdout);
n=getint(),m1=getint(),m2=getint(),Q=getint();
for(int i=1;i<=m1;i++)bian1[i].x=getint(),bian1[i].y=getint(),bian1[i].w=getint();
for(int i=1;i<=m2;i++)bian2[i].x=getint(),bian2[i].y=getint(),bian2[i].w=getint();
kruskal1(),kruskal2(),dfs(1);
for(int i=1;i<=m2;i++)
solve(i);
sort(upt+1,upt+n);
upt[0].x=-INF,upt[0].val=totlen-1ll*(n-1)*INF,upt
.x=INF;
for(int i=1;i<n;i++)
upt[i].val=upt[i-1].val+1ll*(n-i*2+1)*(upt[i].x-upt[i-1].x)-(upt[i].w1+upt[i].x)+(upt[i].w2-upt[i].x);
for(int i=1;i<=Q;i++)q[i].x=getint(),q[i].id=i;
sort(q+1,q+Q+1);
int p=0;
for(int i=1;i<=Q;i++)
{
while(q[i].x>=upt[p+1].x)p++;
ans[q[i].id]=upt[p].val+1ll*(n-p*2-1)*(q[i].x-upt[p].x);
}
for(int i=1;i<=Q;i++)
cout<<ans[i]<<'\n';
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: