您的位置:首页 > 其它

[BZOJ2959]长跑 LCT+双联通分量+并查集

2018-01-18 20:21 387 查看
首先在一个边双联通分量中所有点的贡献是都可以算入的。但是因为有加边操作,考虑用LCT来维护缩边双之后的树。

若一次连接的(x,y)在同一棵树上,就把x到y的路径提出来,缩成一个点。这可能会导致其他某些点的父亲标号改变,所以调用父亲之前一定要用并查集更新一下。

然后因为只有加边,判断在不在一棵树上最好也用并查集,用找根操作常数略大。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 150010
using namespace std;
int n,m,fa
,w
,be
;
int read()
{
int x=0;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
int getfa(int v)
{
if(fa[v]==v) return v;
return(fa[v]=getfa(fa[v]));
}
int getbe(int v)
{
if(be[v]==v) return v;
return (be[v]=getbe(be[v]));
}
struct tree;
tree *a
;
struct tree
{
int t,sum,id;
tree *s[2],*f;
bool rev;
tree(){t=sum=0;rev=0;s[0]=s[1]=f=NULL;}
inline bool nfa()
{
if(f) f=a[getfa(f->id)];
}
inline bool isroot()
{
nfa();
return (!f)||(f->s[0]!=this&&f->s[1]!=this);
}
inline bool son()
{
return f->s[1]==this;
}
inline void update()
{
sum=t+(s[0]?s[0]->sum:0)+(s[1]?s[1]->sum:0);
}
inline void reverse()
{
rev^=1;swap(s[0],s[1]);
}
inline void pushdown()
{
if(rev)
{
if(s[0]) s[0]->reverse();
if(s[1]) s[1]->reverse();
rev=0;
}
}
void rotate()
{
pushdown();
bool b=son()^1;
f->s[b^1]=s[b];
if(s[b]) s[b]->f=f;
s[b]=f;f=f->f;s[b]->f=this;
if(f&&f->s[0]==s[b]) f->s[0]=this;
else if(f&&f->s[1]==s[b]) f->s[1]=this;
s[b]->update();
update();
}
void splay()
{
while(!isroot())
if(f->isroot())  f->pushdown(),rotate();
else
{
f->f->nfa();
f->f->pushdown();
f->pushdown();
if(son()^f->son()) f->rotate();
else rotate();
rotate();
}
}
void access()
{
for(tree *x=this,*y=NULL;x;y=x,x->nfa(),x=x->f)
x->splay(),x->pushdown(),x->s[1]=y,x->update();
}
void makeroot()
{
access();
splay();
reverse();
}
void link(tree *y)
{
makeroot();
f=y;
}
void split(tree *y)
{
y->makeroot();
access();
splay();
}
void modify(int c)
{
splay();
t=sum=c;
}
void merge(tree *x)
{
if(x!=this) x->t+=t;
if(getfa(x->id)!=getfa(id)) fa[fa[id]]=fa[x->id];
if(s[0]) s[0]->merge(x);
if(s[1]) s[1]->merge(x);
s[0]=s[1]=f=NULL;
if(x!=this)t=sum=0;
rev=0;
}
};
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
w[i]=read();
(a[i]=new tree)->modify(w[i]);
a[i]->id=fa[i]=be[i]=i;
}
while(m--)
{
int opt=read(),x=read(),y=read();
if(opt!=2) x=getfa(x),y=getfa(y);
if(opt==1)
{
if(getbe(x)!=getbe(y)) be[be[y]]=be[x],a[x]->link(a[y]);
else if(x!=y)
{
a[x]->split(a[y]);
a[x]->merge(a[x]);
}
}
if(opt==2)
{
getfa(x);
a[fa[x]]->modify(a[fa[x]]->t-w[x]+y);
w[x]=y;
}
if(opt==3)
{
if(getbe(x)!=getbe(y)) {puts("-1");continue;}
a[x]->split(a[y]);
printf("%d\n",a[x]->sum);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: