①洞穴勘测 bzoj2049

题意:由若干个操作,每次加入/删除两点间的一条边,询问某两点是否连通。保证任意时刻图都是一个森林。(两点之间至多只有一条路径)

这就是个link+cut+find root的裸题啦。

LCT实现的时候注意在splay的时候要提前把所有点pushdown一下,详见代码。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int ch[SZ][2],fa[SZ];
bool rev[SZ];
bool top(int x) {return !(ch[fa[x]][0]==x||ch[fa[x]][1]==x);}
void pd(int x)
{
if(!rev[x]) return;
rev[x]=0;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
void rot(int x)
{
if(top(x)) return;
int y=fa[x],c=ch[y][0]==x;
int f=fa[y];
if(!top(y)) ch[f][ch[f][1]==y]=x; //不能直接判f
if(ch[x][c]) fa[ch[x][c]]=y;
ch[y][!c]=ch[x][c];
ch[x][c]=y; fa[x]=f; fa[y]=x;
//upd(y); upd(x);
}
int ss[SZ],sn;
void splay(int x)
{
sn=0;
for(int c=x;;c=fa[c])
{
ss[++sn]=c;
if(top(c)) break;
}
while(sn) pd(ss[sn--]);
while(!top(x))
{
int y=fa[x];
if(!top(y))
{
if(ch[fa[y]][0]==y^ch[y][0]==x) rot(x);
else rot(y);
}
rot(x);
}
}
void access(int x)
{
for(int c=0;x;c=x,x=fa[x]) splay(x), ch[x][1]=c;
}
void makeroot(int x) {access(x); splay(x); rev[x]^=1;}
void link(int a,int b) {makeroot(a); fa[a]=b;}
void cut(int a,int b) {makeroot(a); access(b); splay(b); ch[b][0]=fa[a]=0;}
int findroot(int x)
{
access(x); splay(x);
int lc=x;
while(ch[lc][0]) lc=ch[lc][0];
splay(lc); return lc;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
while(q--)
{
char s[20]; int a,b;
scanf("%s%d%d",s,&a,&b);
if(s[0]=='Q')
{
if(findroot(a)==findroot(b)) puts("Yes");
else puts("No");
}
else if(s[0]=='C') link(a,b);
else cut(a,b);
}
}

②树的统计 bzoj1036

题意:给一棵树,要兹磁点权修改,询问两点间路径最大点权/点权和。

其实讲道理的话这题是可以直接上链剖的,但是还是砍手写了个LCT。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int ch[SZ][2],fa[SZ],sum[SZ],vv[SZ],mx[SZ];
bool rev[SZ];
bool top(int x) {return !(ch[fa[x]][0]==x||ch[fa[x]][1]==x);}
void pd(int x)
{
if(!rev[x]) return;
rev[x]=0;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
void upd(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+vv[x];
mx[x]=max(max(mx[ch[x][0]],mx[ch[x][1]]),vv[x]);
}
void rot(int x)
{
if(top(x)) return;
int y=fa[x],c=ch[y][0]==x;
int f=fa[y];
if(!top(y)) ch[f][ch[f][1]==y]=x; //不能直接判f
if(ch[x][c]) fa[ch[x][c]]=y;
ch[y][!c]=ch[x][c];
ch[x][c]=y; fa[x]=f; fa[y]=x;
upd(y); upd(x);
}
int ss[SZ],sn;
void splay(int x)
{
sn=0;
for(int c=x;;c=fa[c])
{
ss[++sn]=c;
if(top(c)) break;
}
while(sn) pd(ss[sn--]);
while(!top(x))
{
int y=fa[x];
if(!top(y))
{
if(ch[fa[y]][0]==y^ch[y][0]==x) rot(x);
else rot(y);
}
rot(x);
}
}
void access(int x)
{
for(int c=0;x;c=x,x=fa[x]) splay(x), ch[x][1]=c, upd(x);
}
void makeroot(int x) {access(x); splay(x); rev[x]^=1;}
void link(int a,int b) {makeroot(a); fa[a]=b;}
void cut(int a,int b) {makeroot(a); access(b); splay(b); ch[b][0]=fa[a]=0;}
int findroot(int x)
{
access(x); splay(x);
int lc=x;
while(ch[lc][0]) lc=ch[lc][0];
splay(lc); return lc;
}
int ea[SZ],eb[SZ];
int main()
{
int n,q; mx[0]=-2000000000; //wtf...
scanf("%d",&n);
for(int i=1;i<n;i++) scanf("%d%d",ea+i,eb+i);
for(int i=1;i<=n;i++) scanf("%d",vv+i), sum[i]=mx[i]=vv[i];
for(int i=1;i<n;i++) link(ea[i],eb[i]);
scanf("%d",&q);
while(q--)
{
char s[20]; int a,b;
scanf("%s%d%d",s,&a,&b);
if(s[0]=='C')
{
vv[a]=b; splay(a); //玄学
}
else
{
makeroot(a);
access(b);
splay(b);
if(s[1]=='M') printf("%d\n",mx[b]);
else printf("%d\n",sum[b]);
}
}
}

③弹飞绵羊 bzoj2002

题意:有两种操作,改变或删除一个点的父亲,询问一个点的深度。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int ch[SZ][2],fa[SZ],siz[SZ];
bool rev[SZ];
bool top(int x) {return !(ch[fa[x]][0]==x||ch[fa[x]][1]==x);}
void pd(int x)
{
if(!rev[x]) return;
rev[x]=0;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
void upd(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void rot(int x)
{
if(top(x)) return;
int y=fa[x],c=ch[y][0]==x;
int f=fa[y];
if(!top(y)) ch[f][ch[f][1]==y]=x; //不能直接判f
if(ch[x][c]) fa[ch[x][c]]=y;
ch[y][!c]=ch[x][c];
ch[x][c]=y; fa[x]=f; fa[y]=x;
upd(y); upd(x);
}
int ss[SZ],sn;
void splay(int x)
{
sn=0;
for(int c=x;;c=fa[c])
{
ss[++sn]=c;
if(top(c)) break;
}
while(sn) pd(ss[sn--]);
while(!top(x))
{
int y=fa[x];
if(!top(y))
{
if(ch[fa[y]][0]==y^ch[y][0]==x) rot(x);
else rot(y);
}
rot(x);
}
}
void access(int x)
{
for(int c=0;x;c=x,x=fa[x]) splay(x), ch[x][1]=c, upd(x);
}
void makeroot(int x) {access(x); splay(x); rev[x]^=1;}
void link(int a,int b) {makeroot(a); fa[a]=b;}
void cut(int a,int b) {makeroot(a); access(b); splay(b); ch[b][0]=fa[a]=0;}
int findroot(int x)
{
access(x); splay(x);
int lc=x;
while(ch[lc][0]) lc=ch[lc][0];
splay(lc); return lc;
}
int tl[SZ];
int main()
{
int n; scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",tl+i);
link(i+1,min(i+1+tl[i],n+1));
}
int q; scanf("%d",&q);
while(q--)
{
int a;
scanf("%d",&a);
if(a==1)
{
int b; scanf("%d",&b); ++b;
makeroot(n+1);
access(b); splay(b);
printf("%d\n",siz[b]-1);
}
else
{
int i; scanf("%d",&i);
cut(i+1,min(i+1+tl[i],n+1));
scanf("%d",tl+i);
link(i+1,min(i+1+tl[i],n+1));
}
}
}

④魔法森林 NOI2014 uoj3 bzoj3669

题意:无向图中一条边有两个权值a和b,求一条从1到n的路径使经过边a的最大值+经过边b的最大值最小。

我们把边权按a排个序,然后我们现在就是要维护每次动态加一条边和求一条从1到n的路径使得经过边b的最大值最小。

如果询问用spfa硬刚的话复杂度玄学,但是在NOI中可以拿到100分(当然UOJ上只能拿到97分

当然我们可以用lct做,也很简单,我们加一条边(x,y,b=v)只要看一下当前x到y的路径上b的最大值,如果根本就不连通或者最大值大于v,我们就把最大的那条边删掉,把这条边加进去。

那么似乎还有一个问题,lct似乎不好维护边权…但仔细想想你只要把边也当成点就行。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 233333
int ch[SZ][2],fa[SZ],sum[SZ],vv[SZ],mx[SZ];
bool rev[SZ];
bool top(int x) {return !(ch[fa[x]][0]==x||ch[fa[x]][1]==x);}
void pd(int x)
{
if(!rev[x]) return;
rev[x]=0;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
void upd(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+vv[x];
if(vv[mx[ch[x][0]]]>vv[mx[ch[x][1]]]&&vv[mx[ch[x][0]]]>vv[x]) mx[x]=mx[ch[x][0]];
else if(vv[mx[ch[x][1]]]>vv[x]) mx[x]=mx[ch[x][1]];
else mx[x]=x; }
void rot(int x)
{
if(top(x)) return;
int y=fa[x],c=ch[y][0]==x;
int f=fa[y];
if(!top(y)) ch[f][ch[f][1]==y]=x; //不能直接判f
if(ch[x][c]) fa[ch[x][c]]=y;
ch[y][!c]=ch[x][c];
ch[x][c]=y; fa[x]=f; fa[y]=x;
upd(y); upd(x);
}
int ss[SZ],sn;
void splay(int x)
{
sn=0;
for(int c=x;;c=fa[c])
{
ss[++sn]=c;
if(top(c)) break;
}
while(sn) pd(ss[sn--]);
while(!top(x))
{
int y=fa[x];
if(!top(y))
{
if(ch[fa[y]][0]==y^ch[y][0]==x) rot(x);
else rot(y);
}
rot(x);
}
}
void access(int x)
{
for(int c=0;x;c=x,x=fa[x]) splay(x), ch[x][1]=c, upd(x);
}
void makeroot(int x) {access(x); splay(x); rev[x]^=1;}
void link(int a,int b) {makeroot(a); fa[a]=b;}
void cut(int a,int b) {makeroot(a); access(b); splay(b); ch[b][0]=fa[a]=0;}
int findroot(int x)
{
access(x); splay(x);
int lc=x;
while(ch[lc][0]) lc=ch[lc][0];
splay(lc); return lc;
}
int getrd(int a,int b) {makeroot(a); access(b); splay(b); return b;}
int n,m;
struct edg {int x,y,a,b;}es[233333];
bool operator < (edg a,edg b) {return a.a<b.a;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d%d",&es[i].x,&es[i].y,&es[i].a,&es[i].b);
sort(es+1,es+1+m);
int ans=2000000000;
for(int i=1;i<=m;i++)
{
int x=es[i].x,y=es[i].y,a=es[i].a,b=es[i].b;
vv[i+n]=b;
if(findroot(x)==findroot(y))
{
int p=mx[getrd(x,y)];
if(vv[p]<=b) continue;
cut(p,es[p-n].x);
cut(p,es[p-n].y);
}
link(x,i+n); link(i+n,y);
if(findroot(1)==findroot(n)) ans=min(ans,vv[mx[getrd(1,n)]]+a);
}
if(ans==2000000000) ans=-1;
printf("%d\n",ans);
}
//似乎有个地方写错了...欢迎hack

LCT裸题泛做的更多相关文章

  1. 历年NOIP水题泛做

    快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时 ...

  2. bzoj2049: [Sdoi2008]Cave 洞穴勘测 lct裸题

    题意:三种操作一种摧毁一条边,一种链接一条边,一种查询两个点是否联通 题解:lct的link和cut即可 /********************************************** ...

  3. bzoj 2002 弹飞绵羊 lct裸题

    上一次用分块过了, 今天换了一种lct(link-cut tree)的写法. 学lct之前要先学过splay. lct 简单的来说就是 一颗树, 然后每次起作用的都是其中的某一条链. 所以每次如果需要 ...

  4. 2019牛客暑期多校训练营(第八场)E:Explorer(LCT裸题 也可用线段树模拟并查集维护连通性)

    题意:给定N,M,然后给出M组信息(u,v,l,r),表示u到v有[l,r]范围的通行证有效.问有多少种通行证可以使得1和N连通. 思路:和bzoj魔法森林有点像,LCT维护最小生成树.  开始和队友 ...

  5. codeforces泛做..

    前面说点什么.. 为了完成日常积累,傻逼呵呵的我决定来一发codeforces 挑水题 泛做.. 嗯对,就是泛做.. 主要就是把codeforces Div.1的ABCD都尝试一下吧0.0.. 挖坑0 ...

  6. 刷题向》POJ2823 单调队列裸题(<不会做,请自裁>系列)

    最近BZOJ炸了,而我的博客上又更新了一些基本知识,所以这里刷一些裸题,用以丰富知识性博客 POJ2823   滑动的窗口 这是一道经典的单调队题,我记得我刚学的时候就是用这道题作为单调队列的例题,算 ...

  7. HAOI2015 泛做

    T1 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的 ...

  8. 生成树题目泛做(AD第二轮)

    题目1: NOI2014 魔法森林 LCT维护MST.解题报告见LOFTER #include <cstdio> #include <iostream> #include &l ...

  9. POJ 3624 Charm Bracelet(01背包裸题)

    Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38909   Accepted: 16862 ...

随机推荐

  1. 【Android】Fragment真正意义上的onResume和onPause

    前言 Fragment虽然有onResume和onPause的,但是这两个方法是Activity的方法,调用时机也是与Activity相同,和ViewPager搭配使用这个方法就很鸡肋了,根本不是你想 ...

  2. Android 中MyApplication

    package liu.basedemo; import android.app.Activity; import android.app.Application; import java.lang. ...

  3. MVP模式在Android项目中的使用

    以前在写项目的时候,没有过多考虑架构模式的问题,因为之前一直做J2EE开发,而J2EE都是采用MVC模式进行开发的,所以在搭建公司项目的时候,也是使用类似MVC的架构(严格来讲,之前的项目还算不上MV ...

  4. iOS之 HTTP、Socket、TCP的区别(易混

    一.HTTP 是一种超文本传输协议,全名hypertext transfer protocol,从字面意思上可以看出该协议用于规定客户端与服务端之间的传输规则, 传输的内容不限于文本(任意类型的数据) ...

  5. JQuery实现当鼠标停留在某区域3秒后执行

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  6. 结对编程-地铁续(有种上个学期OO的既视感)

    我们组比较特殊..三人结对 github:https://github.com/qingchanghan/WPFUI_Metro po一张照片: 石浩然,韩青长.陈彦吉 (台式机真的很高端,分屏贼帅) ...

  7. 使用Gradle构建构建一个Java Web工程及持续集成环境Jenkins配置

    安装Eclipse插件——Buildship 什么是Buildship? Buildship能方便我们通过Eclipse IDE创建和导入Gradle工程,同时还能执行Gradle任务. Eclips ...

  8. TechEd2013 Shanghai Hol Session PPT Share

    上个月去上海参加了TechEd 2013,并且参与了Hands-on-Lab环节,作为讲师引导大家完成<Local DB in WP8>实验的内容.由于实验的内容采用MVVM架构完成,因此 ...

  9. SQL Server 2014新特性——事务持久性控制

    控制事务持久性 SQL Server 2014之后事务分为2种:完全持久, 默认或延迟的持久. 完全持久,当事务被提交之后,会把事务日志写入到磁盘,完成后返回给客户端. 延迟持久,事务提交是异步的,在 ...

  10. Mysql查询阻塞初探

    第一次值班,报警打电话给我说,数据库复制延时一个多小时,那个时候是半夜啊,但我还是很清醒的起来,开机.vpn.登录.show processlist,结果发现情况是这样的: 红线框表示的是当前每个线程 ...