您的位置:首页 > 其它

完全动态最小生成树(sgu529,HNOI2010city)

2014-01-07 15:18 211 查看
对于加边和删边改变成无穷大就好了。

话说HN好喜欢考裸的比较偏的模板题。会就会,不会考场很难想出来吧。

思想很好理解,就是对询问分治,然后缩点递归。和AHOI2013有道题比较类似。

具体实现可以看英文论文和GYZ在WC上讲课的PPT。

网上的代码都是nlog^2 n的,于是我就去写了nlogn的,结果编程能力太弱。

导致代码太丑,常数巨大.实际运行效果不明显。

而且说是完全动态,但是对于动态维护MST,以及维护路径路径问题

分治貌似莫法搞(WC2006),好像只能写动态树

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
using namespace std;
struct Que
{int k,d;}h
;
struct Num
{int a,b;}num
;
struct Ege
{int a,b,c,w;}Eg
,eg[20]
,neg[20]
,nEg
;
int falg,n,m,q,use
,have
,tot[20],t1,t2[20],f
;
bool cmp(Ege a,Ege b)
{
return a.c<b.c;
}
int find(int v)
{
if (f[v]==v) return f[v];
f[v]=find(f[v]);
return f[v];
}
void YES(int t)
{
for (int i=1;i<=m;i++)
{
f[eg[t][i].a]=eg[t][i].a;
f[eg[t][i].b]=eg[t][i].b;
}
for (int i=1;i<=m;i++)
if (use[eg[t][i].w]==1)
f[find(eg[t][i].a)]=find(eg[t][i].b);
for (int i=1;i<=m;i++)
if (use[eg[t][i].w]!=1&&find(eg[t][i].a)!=find(eg[t][i].b))
{
use[eg[t][i].w]=2;
f[find(eg[t][i].a)]=find(eg[t][i].b);
}
}
void No(int t)
{
for (int i=1;i<=m;i++)
{
have[eg[t][i].a]=have[eg[t][i].b]=0;
f[eg[t][i].a]=eg[t][i].a;
f[eg[t][i].b]=eg[t][i].b;
}
int n=0;
for (int i=1;i<=m;i++)
{
if (have[eg[t][i].a]==0) {n++;have[eg[t][i].a]=1;}
if (have[eg[t][i].b]==0) {n++;have[eg[t][i].b]=1;}
}
int tot=0,k=m;
for (int i=1;i<=m;i++)
if (use[eg[t][i].w]!=1)
{
if (f[find(eg[t][i].a)]!=find(eg[t][i].b))
{
f[find(eg[t][i].a)]=find(eg[t][i].b);
tot++;
if (n-1==tot) {k=i;break;}
} else use[eg[t][i].w]=3;
}
for (int i=k+1;i<=m;i++)
if (!use[eg[t][i].w])
use[eg[t][i].w]=3;

}
int kru(int k,int d,int t)
{
if (tot[t]==1) return d;
if (eg[t][1].w==k) eg[t][1].c=d;
else eg[t][2].c=d;
if (eg[t][1].c<eg[t][2].c) return eg[t][1].c;
return eg[t][2].c;
}
void hebin(int t,int m1)
{
int l1=1,l2=1,m2=t1;
for (int i=1;i<=m1;i++)
{
use[eg[t][i].w]=0;
num[eg[t][i].w].a=eg[t][i].a;
num[eg[t][i].w].b=eg[t][i].b;
}
for (int i=1;i<=m2;i++)
use[Eg[i].w]=1;
for (int i=1;i<=m1;i++)
{
while (l1<=m1&&use[eg[t][l1].w])l1++;
if (l1>m1||(l2<=m2&&Eg[l2].c<eg[t][l1].c)) nEg[i]=Eg[l2++];
else nEg[i]=eg[t][l1++];
}
for (int i=1;i<=m1;i++)
{
eg[t][i]=nEg[i];
eg[t][i].a=num[eg[t][i].w].a;
eg[t][i].b=num[eg[t][i].w].b;
}
}
void deal(int l,int r,int t,long long sum)
{
m=tot[t];
for (int i=1;i<=m;i++)
use[eg[t][i].w]=0;
for (int i=l;i<=r;i++)
use[h[i].k]=1;
YES(t);No(t);
falg=0;
for (int i=1;i<=m;i++)
{
f[eg[t][i].a]=eg[t][i].a;
f[eg[t][i].b]=eg[t][i].b;
}
int &nm=tot[t+1];
nm=0;
for (int i=1;i<=m;i++)
if (use[eg[t][i].w]==2)
{
f[find(eg[t][i].a)]=find(eg[t][i].b);
sum+=eg[t][i].c;
}
for (int i=1;i<=m;i++)
if (use[eg[t][i].w]==0||use[eg[t][i].w]==1&&find(eg[t][i].a)!=find(eg[t][i].b))
{
++nm;
eg[t+1][nm].a=find(eg[t][i].a);
eg[t+1][nm].b=find(eg[t][i].b);
eg[t+1][nm].c=eg[t][i].c;
eg[t+1][nm].w=eg[t][i].w;
}

if (l==r)
{
printf("%I64d\n",sum+kru(h[l].k,h[l].d,t+1));
t1=1;
Eg[t1].c=h[l].d;Eg[t1].w=h[l].k;
return ;
}
int mid=(l+r)/2;
deal(l,mid,t+1,sum);
t2[t]=t1;
for (int i=1;i<=t1;i++)
neg[t][i]=Eg[i];
hebin(t+1,nm);
t1=0;
deal(mid+1,r,t+1,sum);
int l1=1,l2=1,t3=0;
for (int i=1;i<=t2[t];i++)
use[neg[t][i].w]=0;
for (int i=1;i<=t1;i++)
use[Eg[i].w]=1;
while (l1<=t1||l2<=t2[t])
{
while (l2<=t2[t]&&use[neg[t][l2].w])l2++;
if (l1>t1&&l2>t2[t]) break;
if (l2>t2[t]||(l1<=t1&&Eg[l1].c<neg[t][l2].c)) nEg[++t3]=Eg[l1++];
else nEg[++t3]=neg[t][l2++];
}
t1=t3;
for (int i=1;i<=t1;i++)
Eg[i]=nEg[i];
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&Eg[i].a,&Eg[i].b,&Eg[i].c);
Eg[i].w=i;
}
for (int i=1;i<=q;i++)
scanf("%d%d",&h[i].k,&h[i].d);
sort(Eg+1,Eg+1+m,cmp);
tot[0]=m;
for(int i=1;i<=m;i++)
eg[0][i]=Eg[i];
deal(1,q,0,0);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归