LCT真是灵活好用…

LCT的基本思想与树链剖分差不多,都是把树剖成一条条链,只不过LCT用的是SPLAY维护的,而且,SPLAY的链是会变化的,不像剖分是定死的。

LCT最重要的操作就是access(有的地方叫expose),access(po)之后就把po到树的root这条路径变成一条链。

具体实现的话,直接向上一直连就行了,效率可以证明是O(lgn)的。

还有就是两个操作,link和cut。

cut不难,直接找到这条边断掉即可。

link的话,因为splay是用深度维护的,我们只需要access其中一个点,然后再将这个点打上翻转记号,这个点就会成为其所在的树的根,再将其接到另外一个点之下,就行了。

接下来是代码,因为前段时间BZ倒了,所以直接上的是伍一鸣的tree。

这题就是一个裸的LCT,splay上标记的打法与BZ的某道线段树题奇像。

Tsinsen1303/BZOJ2631

 /**************************************************************
Problem: 2631
User: zhuohan123
Language: C++
Result: Accepted
Time:12260 ms
Memory:9836 kb
****************************************************************/ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned int uint;
const int mod=;
int n,q;
struct node
{
int f,s[],ws,size;//splay tree
int head;//tree
bool rev;
uint num,sum,add,mul;
}p[];int pnum,root;
struct edge{int to,next;}g[];int gnum;
inline void addedge(int from,int to)
{
g[++gnum].to=to;g[gnum].next=p[from].head;p[from].head=gnum;
} inline void iadd(uint &x,uint y){x=(x+y)%mod;}
inline void imul(uint &x,uint y){x=(x*y)%mod;}
inline void modify(int po,uint m,uint a)
{
if(m!=)
{
imul(p[po].num,m);
imul(p[po].sum,m);
imul(p[po].mul,m);
imul(p[po].add,m);
}
if(a)
{
iadd(p[po].num,a);
iadd(p[po].sum,a*p[po].size%mod);
iadd(p[po].add,a);
}
}
inline void reverse(int po)
{
if(p[po].rev)
{
swap(p[po].s[],p[po].s[]);
if(p[po].s[])p[p[po].s[]].rev^=,p[p[po].s[]].ws^=;
if(p[po].s[])p[p[po].s[]].rev^=,p[p[po].s[]].ws^=;
p[po].rev^=;
}
}
inline void pushdown(int po)
{
if(p[po].mul!=||p[po].add!=)
{
if(p[po].s[])modify(p[po].s[],p[po].mul,p[po].add);
if(p[po].s[])modify(p[po].s[],p[po].mul,p[po].add);
p[po].mul=;p[po].add=;
}
}
inline void maintain(int po)
{
p[po].sum=p[po].num;
if(p[po].s[])iadd(p[po].sum,p[p[po].s[]].sum);
if(p[po].s[])iadd(p[po].sum,p[p[po].s[]].sum);
p[po].size=;
if(p[po].s[])p[po].size+=p[p[po].s[]].size;
if(p[po].s[])p[po].size+=p[p[po].s[]].size;
}
inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}
inline bool isroot(int po)
{
return !p[po].f||(p[p[po].f].s[]!=po&&p[p[po].f].s[]!=po);
}
inline void rotate(int po,bool ws)
{
int son=p[po].s[ws];
if(isroot(po))p[son].f=p[po].f;
else setson(p[po].f,son,p[po].ws);
setson(po,p[son].s[!ws],ws);
setson(son,po,!ws);
maintain(po);maintain(son);
}
inline int splay(int po)
{
while(!isroot(po))
{
int fa=p[po].f,gf=p[fa].f;
reverse(gf);reverse(fa);reverse(po);
pushdown(gf);pushdown(fa);pushdown(po);
if(isroot(fa)){rotate(fa,p[po].ws);break;}
if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
rotate(fa,p[po].ws);
}
reverse(po);
pushdown(po);
maintain(po);
return po;
}
inline void access(int po)
{
for(int last=;po;last=po,po=p[po].f)
{
splay(po);
setson(po,last,);
maintain(po);
}
}
inline void makeroot(int po)
{
access(po);
splay(po);
p[po].rev^=;
}
inline void link(int u,int v)
{
makeroot(u);
p[u].f=v;
}
inline void cut(int u,int v)
{
access(v);
splay(u);
if(p[u].f==v)p[u].f=;
else
{
access(u);splay(v);
p[v].f=;
}
}
inline void change(int u,int v,uint m,uint a)
{
access(v);
for(int last=;u;last=u,u=p[u].f)
{
splay(u);
if(!p[u].f)
{
if(last)modify(last,m,a);
if(p[u].s[])modify(p[u].s[],m,a);
imul(p[u].num,m);
iadd(p[u].num,a);
}
setson(u,last,);
maintain(u);
}
}
inline uint getans(int u,int v)
{
access(v);
for(int last=;u;last=u,u=p[u].f)
{
splay(u);
if(!p[u].f)
{
uint ans=p[u].num;
if(last)iadd(ans,p[last].sum);
if(p[u].s[])iadd(ans,p[p[u].s[]].sum);
return ans;
}
setson(u,last,);
maintain(u);
}
}
void dfs(int po)
{
p[po].s[]=p[po].s[]=p[po].add=p[po].rev=;
p[po].num=p[po].sum=p[po].mul=p[po].size=;
for(int i=p[po].head;i;i=g[i].next)
if(g[i].to!=p[po].f)
{
p[g[i].to].f=po;
dfs(g[i].to);
}
}
int main(int argc, char *argv[])
{
//freopen("1.in","r",stdin);freopen("1.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
addedge(u,v);addedge(v,u);
}
dfs();
while(q--)
{
char op[];scanf("%s",op);
if(op[]=='+')
{
int u,v,num;scanf("%d%d%d",&u,&v,&num);
change(u,v,,num%mod);
}
if(op[]=='*')
{
int u,v,num;scanf("%d%d%d",&u,&v,&num);
change(u,v,num%mod,);
}
if(op[]=='-')
{
int u1,v1,u2,v2;scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
cut(u1,v1);link(u2,v2);
}
if(op[]=='/')
{
int u,v;scanf("%d%d",&u,&v);
printf("%d\n",getans(u,v));
}
}
return ;
}

还有一道是山东08年的省选题,就是LCT的模板题。

题意相当于维护一个带删除的并查集。

两个点是否在一个子树的判断,只需让两个点都一直沿着它的father跳,最后都会停在它所在的树的根所在的splay的根(好绕!!),只需判断这两个点是否相等即可。

BZOJ2049

 /**************************************************************
Problem: 2049
User: zhuohan123
Language: C++
Result: Accepted
Time:1244 ms
Memory:4560 kb
****************************************************************/ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node{int f,s[];bool ws,rev;}p[];
inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[]!=po&&p[p[po].f].s[]!=po);}
inline void setson(int f,int s,bool ws){p[s].f=f;p[f].s[ws]=s;p[s].ws=ws;}
inline void rotate(int po,bool ws)
{
int son=p[po].s[ws];
if(isroot(po))p[son].f=p[po].f;
else setson(p[po].f,son,p[po].ws);
setson(po,p[son].s[!ws],ws);
setson(son,po,!ws);
}
inline void reverse(int po)
{
if(p[po].rev)
{
swap(p[po].s[],p[po].s[]);
p[p[po].s[]].ws^=;
p[p[po].s[]].ws^=;
p[p[po].s[]].rev^=;
p[p[po].s[]].rev^=;
p[po].rev=false;
}
}
inline int splay(int po)
{
while(!isroot(po))
{
int fa=p[po].f,gf=p[fa].f;
reverse(gf);reverse(fa);reverse(po); if(isroot(fa)){rotate(fa,p[po].ws);break;}
if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
rotate(fa,p[po].ws);
}
reverse(po);
return po;
}
inline void access(int po)
{
for(int last=;po;last=po,po=p[po].f)
setson(splay(po),last,);
}
inline void makeroot(int po)
{
access(po);splay(po);
p[po].rev^=;
}
inline void link(int u,int v)
{
makeroot(u);p[u].f=v;
}
inline void cut(int u,int v)
{
access(u);splay(v);
if(p[v].f==u)p[v].f=;
else
{
access(v);splay(u);
p[u].f=;
}
}
inline bool check(int u,int v)
{
while(p[u].f)u=p[u].f;
while(p[v].f)v=p[v].f;
return u==v;
}
int main(int argc, char *argv[])
{
int n,m;scanf("%d%d",&n,&m);
while(m--)
{
char str[];int u,v;
scanf("%s%d%d",str,&u,&v);
if(str[]=='C')link(u,v);
if(str[]=='D')cut(u,v);
if(str[]=='Q')puts(check(u,v)?"Yes":"No");
}
return ;
}

接下来是最后一个……WC2006的水管局长

题意是维护一个带link与cut的最小生成树…

由于这棵树是会“动”的,所以不能把边权下放到点上,那么就只好把一条边变成一个点,再把这个点与两个端点相连,常数狂增不止。

BZOJ2494

 /**************************************************************
Problem: 2594
User: zhuohan123
Language: C++
Result: Accepted
Time:15728 ms
Memory:53252 kb
****************************************************************/ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int getnum()
{
int ans=;char ch=getchar();
while(ch>''||ch<'')ch=getchar();
while(ch>=''&&ch<='')ans=ans*+ch-'',ch=getchar();
return ans;
}
int n,m,que;
struct point
{
int f,s[];bool ws,rev;
int num,mnum,mpos;
void output(int now)
{
printf("%d f:%d ls:%d rs:%d rev:%d num:%d mnum:%d mpos:%d\n",now,f,s[],s[],rev,num,mnum,mpos);
}
}p[];int pnum;
inline void maintain(int po)
{
p[po].mnum=p[po].num;p[po].mpos=po;
if(p[po].s[]&&p[p[po].s[]].mnum>p[po].mnum)
p[po].mnum=p[p[po].s[]].mnum,p[po].mpos=p[p[po].s[]].mpos;
if(p[po].s[]&&p[p[po].s[]].mnum>p[po].mnum)
p[po].mnum=p[p[po].s[]].mnum,p[po].mpos=p[p[po].s[]].mpos;
}
inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[]!=po&&p[p[po].f].s[]!=po);}
inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}
inline void rotate(int po,bool ws)
{
int son=p[po].s[ws];
if(isroot(po))p[son].f=p[po].f;
else setson(p[po].f,son,p[po].ws);
setson(po,p[son].s[!ws],ws);
setson(son,po,!ws);
maintain(po);maintain(son);
}
inline void reverse(int po)
{
if(p[po].rev)
{
swap(p[po].s[],p[po].s[]);
p[p[po].s[]].ws^=;
p[p[po].s[]].ws^=;
p[p[po].s[]].rev^=;
p[p[po].s[]].rev^=;
p[po].rev=false;
}
}
inline int splay(int po)
{
while(!isroot(po))
{
int fa=p[po].f,gf=p[fa].f;
reverse(gf);reverse(fa);reverse(po);
if(isroot(fa)){rotate(fa,p[po].ws);break;}
if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
rotate(fa,p[po].ws);
}
reverse(po);
return po;
}
inline void access(int po)
{
for(int last=;po;last=po,po=p[po].f)
{
splay(po);
setson(po,last,);
maintain(po);
}
}
inline void makeroot(int po)
{
access(po);splay(po);
p[po].rev^=;
}
inline void link(int u,int v)
{
makeroot(u);p[u].f=v;
}
inline void cut(int u,int v)
{
access(u);splay(v);
if(p[v].f==u)p[v].f=;
else
{
access(v);splay(u);
p[u].f=;
}
}
inline int getmax(int u,int v,int &mpos)
{
access(v);
for(int last=;u;last=u,u=p[u].f)
{
splay(u);
if(!p[u].f)
{
int ans=p[u].num;mpos=u;
if(p[u].s[]&&ans<p[p[u].s[]].mnum)ans=p[p[u].s[]].mnum,mpos=p[p[u].s[]].mpos;
if(last&&ans<p[last].mnum)ans=p[last].mnum,mpos=p[last].mpos;
return ans;
}
setson(u,last,);
maintain(u);
}
return ;
}
struct bian{int u,v,c,can;}b[];
inline bool cmp1(bian a,bian b){return a.u==b.u?a.v<b.v:a.u<b.u;}
inline bool cmp2(bian a,bian b){return a.c<b.c;}
struct question{int p,u,v,pos,c,ans;}q[];
inline bool cmp3(question a,question b){return a.u==b.u?a.v<b.v:a.u<b.u;}
inline bool cmp4(question a,question b){return a.pos<b.pos;}
int fa[];
int gf(int po){return fa[po]==po?po:fa[po]=gf(fa[po]);}
int head[];
struct edge{int to,next;}g[];int gnum;
inline void addedge(int from,int to)
{
g[++gnum].to=to;g[gnum].next=head[from];head[from]=gnum;
g[++gnum].to=from;g[gnum].next=head[to];head[to]=gnum;
}
bian intree[];
int qu[],ql,qr;
void bfs()
{
ql=;qr=;
qu[++qr]=;
while(ql<=qr)
for(int now=qu[ql++],i=head[now];i;i=g[i].next)
if(p[now].f!=g[i].to)
p[qu[++qr]=g[i].to].f=now;
}
int main(int argc, char *argv[])
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=getnum(),m=getnum(),que=getnum();
pnum=n;
for(int i=;i<=m;i++)
{
b[i].u=getnum(),b[i].v=getnum(),b[i].c=getnum();
if(b[i].u>b[i].v)swap(b[i].u,b[i].v);
b[i].can=true;
}
for(int i=;i<=que;i++)
{
q[i].p=getnum(),q[i].u=getnum(),q[i].v=getnum();
if(q[i].u>q[i].v)swap(q[i].u,q[i].v);
q[i].pos=i;
}
sort(b+,b+m+,cmp1);
sort(q+,q+que+,cmp3);
for(int i=,j=;i<=m&&j<=que;i++)
{
while(j<=que&&((q[j].u<b[i].u)||(q[j].u==b[i].u&&q[j].v<b[i].v)||q[j].p==))j++;
if(j<=que&&q[j].u==b[i].u&&q[j].v==b[i].v)b[i].can=false,q[j].c=b[i].c;
}
for(int i=;i<=n;i++)fa[i]=i;
sort(b+,b+m+,cmp2);
for(int i=;i<=m;i++)
if(b[i].can&&gf(b[i].u)!=gf(b[i].v))
{
pnum++;p[pnum].num=b[i].c;
addedge(b[i].u,pnum);
addedge(b[i].v,pnum);
intree[pnum].u=b[i].u;intree[pnum].v=b[i].v;
fa[gf(b[i].u)]=gf(b[i].v);
}
bfs();
for(int i=;i<=pnum;i++)p[i].mnum=p[i].num,p[i].mpos=i;
sort(q+,q+que+,cmp4);
for(int i=que;i;i--)
{
int mpos;
if(q[i].p==)q[i].ans=getmax(q[i].u,q[i].v,mpos);
else if(getmax(q[i].u,q[i].v,mpos)>q[i].c)
{
cut(mpos,intree[mpos].u);
cut(mpos,intree[mpos].v);
intree[mpos].u=q[i].u;
intree[mpos].v=q[i].v;
p[mpos].num=q[i].c;
link(mpos,q[i].u);
link(mpos,q[i].v);
}
}
for(int i=;i<=que;i++)
if(q[i].p==)printf("%d\n",q[i].ans);
return ;
}

LCT小结的更多相关文章

  1. 动态树LCT小结

    最开始看动态树不知道找了多少资料,总感觉不能完全理解.但其实理解了就是那么一回事...动态树在某种意思上来说跟树链剖分很相似,都是为了解决序列问题,树链剖分由于树的形态是不变的,所以可以通过预处理节点 ...

  2. LCT小小结

    模板题P3690 基础题P3203[HNOI2010]弹飞绵羊 \(access\)是搞出一条端点为\(x,y\)的路径 , 且维护的是实子树的信息 . 由于题目比较简单 , \(access\)时还 ...

  3. LCT专题练习

    [bzoj2049]洞穴勘测 http://www.cnblogs.com/Sdchr/p/6188628.html 小结 (1)LCT可以方便维护树的连通性,但是图的连通性的维护貌似很麻烦. [bz ...

  4. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  5. Python自然语言处理工具小结

    Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...

  6. java单向加密算法小结(2)--MD5哈希算法

    上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...

  7. iOS--->微信支付小结

    iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...

  8. iOS 之UITextFiled/UITextView小结

    一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...

  9. K近邻法(KNN)原理小结

    K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...

随机推荐

  1. Oracle private dblink和pubic dblink

    DB : 11.2.0.3.0 Oracle DBLINK 创建分为private 和 public dblink,默认创建的为private ; private dblink 只有创建的schema ...

  2. core java 8~9(GUI & AWT事件处理机制)

    MODULE 8 GUIs--------------------------------GUI中的包: java.awt.*; javax.swing.*; java.awt.event.*; 要求 ...

  3. OpenStack:安装Keystone

    >安装Keystone1. 安装# apt-get install keystone2. 创建dbcreate database keystone;grant all privileges on ...

  4. Libevent windows/linux下编译

    1.windows下: 编译环境: windows xp sp3 + vs2010 (1)    解压libevent-2.0.21-stable.tar.gz到D:\libevent-2.0.21- ...

  5. C#类型的转换:Converter<TInput, TOutput> 委托的使用

    Converter<TInput, TOutput> 委托 表示将对象从一种类型转换为另一种类型的方法. 此委托由 Array 类的 ConvertAll<TInput, TOutp ...

  6. How to Notify Command to evaluate in mvvmlight

    How to Raize Command to evalituate in mvvm In mvvmlight, we bind our control to the relaycommand obj ...

  7. [原]项目进阶 之 集群环境搭建(二)MySQL集群

    上次的博文中我们介绍了一下集群的相关概念,今天的博文我们介绍一下MySQL集群的相关内容. 1.MySQL集群简介 MySQL群集技术在分布式系统中为MySQL数据提供了冗余特性,增强了安全性,使得单 ...

  8. Java BigDecimal大数字操作

    在java中提供了大数字的操作类,即java.math.BinInteger类和java.math.BigDecimal类.这两个类用于高精度计算,其中BigInteger类是针对大整数的处理类,而B ...

  9. asp.net webservice 返回json数据乱码解决方法

    [WebMethod] public void QueryRiskNotice(string phone) { try { var data = _riskNoticeDal.QueryRiskNot ...

  10. hibernate3连oracle的各种坑。。

    坑一:驱动错误导致sql查询不了,升级驱动到最新版即可 2.通过构造函数封装数据时,如果报错无法实例化并且不是因为字段不对应导致的,可以试试把float改为Float之类的包装类