您的位置:首页 > 其它

[NOI2014]魔法森林

2018-03-08 16:30 302 查看

题目

[NOI2014]魔法森林

解析

要求a 与 b 的总和最小 可以按a排序 再以b为权值维护一颗树 LCT维护最小生成树

要解决的问题

将每一条边变为一个点 边权变为点权 举个栗子: u->v有一条边权为w的边 怎LCT连边方式为 u->new->v new的点权为w

不断维护最小生成树 如果新加入的边的 u与v不连通 直接加 如果连通 求u到v路上的最大边权边 将它切掉(其实是切两条边)再加边

边权为b

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=100000+10;
int n,m,blow;
int ans=0x7fffffff;
struct node1
{
int a,b,start,end;
bool operator < (const node1 & o) const
{
return a<o.a;
}
}edge[maxn];
struct node
{
int fa,ch[2]; bool reverse,is_root;
int data,id; int max1,id1;
}T[maxn*10];
int getson(int x)
{
return T[T[x].fa].ch[1]==x;
}
void update(int x)
{
if(x>n)
T[x].max1=T[x].data,T[x].id1=T[x].id;
else T[x].max1=0;
if(T[x].ch[1] && T[x].max1<T[T[x].ch[1]].max1)
{
T[x].max1=T[T[x].ch[1]].max1; T[x].id1=T[T[x].ch[1]].id1;
}
if(T[x].ch[0] && T[x].max1<T[T[x].ch[0]].max1)
{
T[x].max1=T[T[x].ch[0]].max1; T[x].id1=T[T[x].ch[0]].id1;
}
}
void rotate(int x)
{
int son=getson(x),fa=T[x].fa; int g=T[fa].fa;
T[fa].ch[son]=T[x].ch[son^1]; T[fa].fa=x; T[x].fa=g;
if(T[x].ch[son^1]) T[T[x].ch[son^1]].fa=fa;
T[x].ch[son^1]=fa;
if(!T[fa].is_root) T[g].ch[T[g].ch[1]==fa]=x;
else T[x].is_root=true,T[fa].is_root=false;
update(fa); update(x);
}
void pushreverse(int x)
{
if(!x) return;
swap(T[x].ch[0],T[x].ch[1]);
T[x].reverse^=1;
}
void pushdown(int x)
{
if(T[x].reverse)
{
pushreverse(T[x].ch[0]); pushreverse(T[x].ch[1]);
T[x].reverse=false;
}
}
void push(int x)
{
if(!T[x].is_root) push(T[x].fa);
pushdown(x);
}
void splay(int x)
{
push(x);
for(int fa; !T[x].is_root; rotate(x))
{
if(!T[fa=T[x].fa].is_root) rotate(getson(fa)==getson(x)? fa : x);
}
}
void access(int x)
{
for(int y=0; x; x=T[y=x].fa)
{
splay(x); T[T[x].ch[1]].is_root=true; T[T[x].ch[1]=y].is_root=false; update(x);
}
}
void mroot(int x)
{
access(x); splay(x); pushreverse(x);
}
int findroot(int x)
{
while(T[x].fa)
x=T[x].fa;
return x;
}
void link(int x,int y)
{
mroot(x); T[x].fa=y;
}
void cut(int x,int y)
{
mroot(x); access(y); splay(y);
T[x].is_root=true; T[x].fa=T[y].ch[0]=0;
}
int solve(int x)
{
blow=x;
int x1=edge[blow].start,y=edge[blow].end;
int xx=findroot(x1),yy=findroot(y);
//      cout<<x<<' '<<x1<<' '<<y<<' '<<xx<<' '<<yy<<endl;
if(xx!=yy)
{
T[blow+n].data=edge[blow].b; T[blow+n].id=blow+n; link(n+blow,x1); link(n+blow,y);
}
else
{
mroot(x1);
access(y);
splay(y);
if(T[y].max1>edge[blow].b)
{
//              cout<<x<<' '<<T[y].id1<<endl;
T[T[y].id1].id=T[T[y].id1].data=0;
int cc=T[y].id1;//¼Çϵ±Ç°½Úµã£¬cutÖ®ºó¿ÉÄÜ»á¸Ä±ä
cut(edge[cc-n].start,cc); cut(cc,edge[cc-n].end);
T[blow+n].data=edge[blow].b; T[blow+n].id=blow+n; link(x1,n+blow); link(n+blow,y);
}
}
xx=findroot(1),yy=findroot(n);
if(xx!=yy) return -1;
mroot(1); access(n); splay(n);
return T
.max1;
}
int main()
{
freopen("magicalforest.in","r",stdin);
freopen("magicalforest.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=0; i<=n+m; i++)
{
T[i].is_root=true;
}
for(int i=1; i<=m; i++)
{
scanf("%d %d %d %d",&edge[i].start,&edge[i].end,&edge[i].a,&edge[i].b);
}
sort(edge+1,edge+m+1);
bool flag=false; blow=1;
for(int i=1; i<=m; i++)
{
/*      if(i==327)
{
int tmp=solve(i);
if(tmp!=-1 && tmp+i<ans)
{
flag=true;
ans=min(ans,tmp+edge[i].a);
}
continue;
}*/
int tmp=solve(i);
if(tmp!=-1 && tmp+edge[i].a<ans)
{
flag=true;
ans=min(ans,tmp+edge[i].a);
}
}
cout<<(flag? ans:-1)<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: