LCT小结
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小结的更多相关文章
- 动态树LCT小结
最开始看动态树不知道找了多少资料,总感觉不能完全理解.但其实理解了就是那么一回事...动态树在某种意思上来说跟树链剖分很相似,都是为了解决序列问题,树链剖分由于树的形态是不变的,所以可以通过预处理节点 ...
- LCT小小结
模板题P3690 基础题P3203[HNOI2010]弹飞绵羊 \(access\)是搞出一条端点为\(x,y\)的路径 , 且维护的是实子树的信息 . 由于题目比较简单 , \(access\)时还 ...
- LCT专题练习
[bzoj2049]洞穴勘测 http://www.cnblogs.com/Sdchr/p/6188628.html 小结 (1)LCT可以方便维护树的连通性,但是图的连通性的维护貌似很麻烦. [bz ...
- 从零开始编写自己的C#框架(26)——小结
一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...
- Python自然语言处理工具小结
Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...
- java单向加密算法小结(2)--MD5哈希算法
上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...
- iOS--->微信支付小结
iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...
- iOS 之UITextFiled/UITextView小结
一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...
- K近邻法(KNN)原理小结
K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...
随机推荐
- 05-树9 Huffman Codes
哈夫曼树 Yes 需满足两个条件:1.HuffmanTree 结构不同,但WPL一定.子串WPL需一致 2.判断是否为前缀码 开始判断用的strstr函数,但其传值应为char *,不能用在strin ...
- Keil的使用方法 - 常用功能(一)
Ⅰ.概述 学习一门软件的开发,开发工具的掌握可以说尤为重要.由于Keil集成开发工具支持多种MCU平台的开发,是市面上比较常见的,也是功能比较强大一款IDE.所以,对于大多数人说,选择Keil几乎是单 ...
- python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)
1.函数对象 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函 ...
- C基础 北京大公司面试简单总结
作者有话说 这是关于程序员面试的一篇文章, 希望对你有帮助. 干了快3年了. 可以简单参考, 对比总结.虽然本人很水. 很喜欢当前做的手游项目.做的很认真.后端每个人技术都很好.但是结果都不如意.在死 ...
- XSS的原理分析与解剖[转http://www.freebuf.com/articles/web/40520.html]
0×01 前言: <xss攻击手法>一开始在互联网上资料并不多(都是现成的代码,没有从基础的开始),直到刺的<白帽子讲WEB安全>和cn4rry的<XSS跨站脚本攻击剖析 ...
- Swift学习初步(一)
前几天刚刚将有关oc的教程草草的看了一遍,发现oc其实也不像传说的那么难.今天又开始马不停蹄的学习Swift因为我很好奇,到底苹果出的而且想要代替oc的编程语言应该是个什么样子呢?看了网上的一些中文教 ...
- plist 读取 swift
// // ViewController.swift // plist读写 // // Created by mac on 15/7/13. // Copyright (c) 2015年 fangyu ...
- Haskell 趣学指南 入门笔记(二)
显示类型声明,Haskell是不用定义类型的原因,很像python 想要确定某个表达式的类型 *Main> :t 'a' 'a' :: Char *Main> :t True True : ...
- tcp传输黏包
tcp传输黏包 tcpip协议使用"流式"(套接字)进行数据的传输,就是说它保证数据的可达以及数据抵达的顺序,但并不保证数据是否在你接收的时候就到达,特别是为了提高效率,充分利用带 ...
- Ionic 2 Guide
Ionic 2 Guide 最近一直没更新博客,业余时间都在翻译Ionic2的文档.之前本来是想写一个入门,后来觉得干脆把官方文档翻译一下算了,因为官方文档就是最好的入门教程.后来越翻译越觉得这个事情 ...