我终于理解了 \(LCT\)!!!想不到小蒟蒻有一天理解了!!!

1、【模板】Link Cut Tree

存个板子

#include <bits/stdc++.h>
using namespace std;
const int maxn=300000+10;
int n,m,a[maxn],ch[maxn][2],fa[maxn],val[maxn],sta[maxn],top;
bool rev[maxn]; inline void reverse(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushup(int x){
val[x]=val[ch[x][0]]^val[ch[x][1]]^a[x];
}
inline void pushdown(int x){
if(rev[x]){
rev[x]=0;
if(ch[x][0]) reverse(ch[x][0]);
if(ch[x][1]) reverse(ch[x][1]);
}
}
inline bool nrt(int x){
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[y][k]=u;ch[x][k^1]=y;
if(u) fa[u]=y;fa[y]=x;fa[x]=z;
val[x]=val[y];pushup(y);
}
inline void splay(int x){
int y,z;top=0;
for(y=x;nrt(y);y=fa[y]) sta[top++]=y;
pushdown(y);
while(top) pushdown(sta[--top]);
while(nrt(x)){
y=fa[x],z=fa[y];
if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
rotate(x);
}
}
inline void access(int x){
int y=0;
for(;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
access(x),splay(x),reverse(x);
}
inline int findroot(int x){
access(x),splay(x);
for(;ch[x][0];x=ch[x][0]) pushdown(x);
return x;
}
inline void split(int x,int y){
makeroot(x),access(y),splay(y);
}
inline void link(int x,int y){
makeroot(x);
if(findroot(y)!=x)
fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&fa[x]==y&&!ch[x][1])
fa[x]=ch[y][0]=0,pushup(y);
}
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
} int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++){
val[i]=a[i]=read();
fa[i]=ch[i][0]=ch[i][1]=0;
}
int opt,x,y;
for(int i=1;i<=m;i++){
opt=read(),x=read(),y=read();
if(opt==0) split(x,y),printf("%d\n",val[y]);
if(opt==1) link(x,y);
if(opt==2) cut(x,y);
if(opt==3) splay(x),a[x]=y,pushup(x);
}
return 0;
}

2、[COCI 2009] OTOCI / 极地旅行社

其实就是 \(pushup\) 改了一下

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=30000+10;
int n,q,a[maxn],ch[maxn][2],fa[maxn],val[maxn],sta[maxn],top;
bool rev[maxn]; inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
inline void reverse(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushup(int x){
val[x]=val[ch[x][0]]+val[ch[x][1]]+a[x];
}
inline void pushdown(int x){
if(rev[x]){
rev[x]=0;
if(ch[x][0]) reverse(ch[x][0]);
if(ch[x][1]) reverse(ch[x][1]);
}
}
inline bool nrt(int x){
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[y][k]=u;ch[x][k^1]=y;
if(u) fa[u]=y;fa[y]=x;fa[x]=z;
val[x]=val[y];pushup(y);
}
inline void splay(int x){
int y,z;top=0;
for(y=x;nrt(y);y=fa[y]) sta[top++]=y;
pushdown(y);
while(top) pushdown(sta[--top]);
while(nrt(x)){
y=fa[x],z=fa[y];
if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
rotate(x);
}
}
inline void access(int x){
int y=0;
for(;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
access(x),splay(x),reverse(x);
}
inline int findroot(int x){
access(x),splay(x);
for(;ch[x][0];x=ch[x][0]) pushdown(x);
return x;
}
inline void split(int x,int y){
makeroot(x),access(y),splay(y);
}
inline int link(int x,int y){
makeroot(x);
if(findroot(y)!=x){
fa[x]=y,pushup(y);
return 1;
}
return 0;
}
inline void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&fa[x]==y&&!ch[x][1])
fa[x]=ch[y][0]=0,pushup(y);
} int main()
{
n=read();
for(int i=1;i<=n;i++)
val[i]=a[i]=read();
char opt[20];int x,y;
q=read();
for(int i=1;i<=q;i++){
scanf("%s",opt);
x=read(),y=read();
if(opt[0]=='b'){
if(link(x,y)) printf("yes\n");
else printf("no\n");
}
if(opt[0]=='p'){
splay(x),a[x]=y,pushup(x);
}
if(opt[0]=='e'){
makeroot(x);
if(findroot(y)!=x)
printf("impossible\n");
else split(x,y),printf("%d\n",val[y]);
}
}
return 0;
}

3、[WC2006]水管局长

删边操作不好处理,所以倒过来。

动态查询最大边权的最小值,先做一遍 \(Kruskal\),然后每次选一条最大的边权,如果当前加边的边权比最大的边权小,那么 \(Cut\) 掉原来的边然后 \(Link\) 一下现在的边。

边权不好处理,还要转化成点权,用虚点法。

\(Code\ Below:\)

#include <bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int maxn=1000000+10;
int n,m,Q,ch[maxn][2],fa[maxn],val[maxn],Max[maxn],sta[maxn],f[maxn],ans[maxn],top;
bool rev[maxn],vis[maxn];
struct Edge{
int x,y,w;
}e[maxn];
struct Query{
int op,x,y,id;
}q[maxn];
map<pii,int> mp;
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
inline void reverse(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushup(int x){
Max[x]=x;
if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
}
inline void pushdown(int x){
if(rev[x]){
rev[x]=0;
if(ch[x][0]) reverse(ch[x][0]);
if(ch[x][1]) reverse(ch[x][1]);
}
}
inline bool nrt(int x){
return x==ch[fa[x]][0]||x==ch[fa[x]][1];
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[y][k]=u;ch[x][k^1]=y;
if(u) fa[u]=y;fa[y]=x;fa[x]=z;
pushup(y);pushup(x);
}
inline void splay(int x){
int y,z;top=0;
for(y=x;nrt(y);y=fa[y]) sta[++top]=y;
pushdown(y);
while(top) pushdown(sta[top--]);
while(nrt(x)){
y=fa[x],z=fa[y];
if(nrt(y)) rotate((x==ch[y][1])^(y==ch[z][1])?x:y);
rotate(x);
}
}
inline void access(int x){
int y=0;
for(;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
access(x),splay(x),reverse(x);
}
inline int findroot(int x){
access(x),splay(x);
for(;ch[x][0];x=ch[x][0]) pushdown(x);
return x;
}
inline void split(int x,int y){
makeroot(x),access(y),splay(y);
}
inline void link(int x,int y){
makeroot(x);
if(findroot(y)!=x)
fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&fa[x]==y&&!ch[y][1])
fa[x]=ch[y][0]=0,pushup(y);
}
int find(int x){
return (x==f[x])?x:f[x]=find(f[x]);
} int main()
{
n=read(),m=read(),Q=read();
for(int i=1;i<=m;i++){
e[i].x=read(),e[i].y=read(),e[i].w=read();
if(e[i].x>e[i].y) swap(e[i].x,e[i].y);
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
mp[make_pair(e[i].x,e[i].y)]=i;
val[i+n]=e[i].w;Max[i+n]=i+n;
}
for(int i=1;i<=Q;i++){
q[i].op=read(),q[i].x=read(),q[i].y=read();
if(q[i].op==2){
if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
q[i].id=mp[make_pair(q[i].x,q[i].y)];
vis[q[i].id]=1;
}
}
int x,y,t,a,b,tot=0;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
if(!vis[i]){
x=e[i].x;y=e[i].y;
a=find(x);b=find(y);
if(a!=b){
link(x,i+n);link(y,i+n);
f[a]=b;tot++;
if(tot==n-1) break;
}
}
}
for(int i=Q;i>=1;i--){
x=q[i].x;y=q[i].y;
if(q[i].op==1){
split(x,y);ans[i]=val[Max[y]];
}
else {
split(x,y);t=Max[y];
if(val[q[i].id+n]<val[t]){
cut(e[t-n].x,t);cut(e[t-n].y,t);
link(x,q[i].id+n);link(y,q[i].id+n);
}
}
}
for(int i=1;i<=Q;i++)
if(q[i].op==1) printf("%d\n",ans[i]);
return 0;
}

4、[NOI2014]魔法森林

边权先按 \(b\) 排序,然后维护一个 \(a\) 的最大边权的最小值,把边权转换成点权。

\(Code\ Below:\)

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
const int inf=0x3f3f3f3f;
int n,m,ch[maxn][2],fa[maxn],val[maxn],Max[maxn],sta[maxn],top,ans=inf;
bool rev[maxn]; struct Edge{
int x,y,a,b;
}e[maxn]; bool cmp(Edge x,Edge y){
return x.b<y.b;
} inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
} inline void reverse(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushup(int x){
Max[x]=x;
if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
}
inline void pushdown(int x){
if(rev[x]){
rev[x]=0;
if(ch[x][0]) reverse(ch[x][0]);
if(ch[x][1]) reverse(ch[x][1]);
}
}
inline bool nrt(int x){
return x==ch[fa[x]][0]||x==ch[fa[x]][1];
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[y][k]=u;ch[x][k^1]=y;
if(u) fa[u]=y;fa[y]=x;fa[x]=z;
pushup(y);pushup(x);
}
inline void splay(int x){
int y,z;top=0;
for(y=x;nrt(y);y=fa[y]) sta[++top]=y;
pushdown(y);
while(top) pushdown(sta[top--]);
while(nrt(x)){
y=fa[x],z=fa[y];
if(nrt(y)) rotate((x==ch[y][1])^(y==ch[z][1])?x:y);
rotate(x);
}
}
inline void access(int x){
int y=0;
for(;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline int findroot(int x){
access(x),splay(x);
for(;ch[x][0];x=ch[x][0]) pushdown(x);
return x;
}
inline void makeroot(int x){
access(x),splay(x),reverse(x);
}
inline int split(int x,int y){
makeroot(x),access(y),splay(y);
return Max[y];
}
inline void link(int x,int y){
makeroot(x);
if(findroot(y)!=x)
fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&fa[x]==y&&!ch[y][1])
fa[x]=ch[y][0]=0,pushup(y);
} int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
val[i+n]=e[i].a;
Max[i+n]=i+n;
}
int x,y,t;bool flag=0;
for(int i=1;i<=m;i++){
x=e[i].x;y=e[i].y;flag=1;
if(findroot(x)==findroot(y)){
t=split(x,y);
if(val[t]>e[i].a) cut(e[t-n].x,t),cut(e[t-n].y,t);
else flag=0;
}
if(flag) link(x,i+n),link(y,i+n);
if(findroot(1)==findroot(n)) ans=min(ans,e[i].b+val[split(1,n)]);
}
printf("%d\n",(ans==inf)?-1:ans);
return 0;
}

[学习笔记]Link-Cut Tree的更多相关文章

  1. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  2. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

  3. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  4. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  5. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

  6. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  7. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  8. bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

    link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...

  9. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  10. [CodeForces - 614A] A - Link/Cut Tree

    A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...

随机推荐

  1. H3 android 系统编译

    http://bbs.ickey.cn/group-topic-id-57981.html [Orange Pi PC试用体验]11编译android源码笔记 编译android和编译linux有点类 ...

  2. HDU 6185(打表代码

    /** @xigua */ #include <cstdio> #include <cmath> #include <iostream> #include < ...

  3. oracle 重建分区索引

    分区表的所有分区相当于一个单独的表. 创建在分区表上的索引,就相当于在所有分区上单独创建的索引(主键索引除外). 重建分区表的索引回报: ORA-14086:不能将分区索引作为整体重建. so,重建语 ...

  4. 有关PHP 10条有用的建议--转(柒捌玖零)

    1.使用ip2long() 和long2ip()函数来把IP地址转化成整型存储到数据库里. 这种方法把存储空间降到了接近四分之一(char(15)的15个字节对整形的4个字节),计算一个特定的地址是不 ...

  5. 811. Subdomain Visit Count

    这题主要难在构建关联容器,方法很多,但是核心都是把原字符串一截一截减下来处理,先把前面用空格隔开的次数转化为整数,然后处理后面的多层子域. 方法一,查找标志字符,用标志字符把字符串分成几段 stati ...

  6. 2018.10.25 bzoj4517: [Sdoi2016]排列计数(组合数学)

    传送门 组合数学简单题. Ans=(nm)∗1Ans=\binom {n} {m}*1Ans=(mn​)∗1~(n−m)(n-m)(n−m)的错排数. 前面的直接线性筛逆元求. 后面的错排数递推式本蒟 ...

  7. Java 学习之集合类(Collections)

    Collection(集合类) 我们是使用数组来保存数据,但是他的长度一旦创建,就已经确定了,当我们要动态传入穿值,数组就有些局限了,集合类就孕育而生:所谓集合,就是来保存,盛装数据,也可称为容器类: ...

  8. ubuntu16.04无法关机解决方法

    11 down vote   In my case these simple steps worked for me fine: Press Ctrl+Alt+T to go to a termina ...

  9. .Net实现Windows服务安装完成后自动启动的两种方法

    考虑到部署方便,我们一般都会将C#写的Windows服务制作成安装包.在服务安装完成以后,第一次还需要手动启动服务,这样非常不方便. 方法一:在安装完成事件里面调用命令行的方式启动服务 此操作之前要先 ...

  10. Java潜在的坑持续总结

    1.Java里如果有if (foo == 0),如果foo是null这里居然是会抛NPE异常而不是返回false: 2.Java里整形数值不能用==来比较,因为只有区间是[-128,127]的才能这么 ...