①洞穴勘测 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. ios UI 适配布局相关文章

    1. http://lvwenhan.com/ios/430.html 2 . http://blog.csdn.net/liangliang103377/article/details/400822 ...

  2. 【原+转】用CMake代替makefile进行跨平台交叉编译

    在开始介绍如何使用CMake编译跨平台的静态库之前,先讲讲我在没有使用CMake之前所趟过的坑.因为很多开源的程序,比如png,都是自带编译脚本的.我们可以使用下列脚本来进行编译: ./configu ...

  3. AOP的实现机制

    1 AOP各种的实现 AOP就是面向切面编程,我们可以从几个层面来实现AOP. 在编译器修改源代码,在运行期字节码加载前修改字节码或字节码加载后动态创建代理类的字节码,以下是各种实现机制的比较. 类别 ...

  4. Linux- Nginx简单的负载均衡(一)

    这里先进行简单的nginx负载,安装nginx这里就不多说了,我们情景假设在已经安装好了nginx上: 1)查询nginx中的upstrea负载均衡模块  默认是有安装的.进入nginx源码目录中 . ...

  5. 各类 HTTP 返回状态代码详解

    完整版 1**(信息类):表示接收到请求并且继续处理 100——客户必须继续发出请求 101——客户要求服务器根据请求转换HTTP协议版本 2**(响应成功):表示动作被成功接收.理解和接受 200— ...

  6. WordCount的程序设计没写出来怎么办

    这一星期要完成三个小作业,完成前两个已经让我很吃力的了,现在这个WordCount的编程我都没有头绪,不知道从何下手.虽然要求很看起来很简单,可是不知道怎么去设计这个程序,这两天我也在积极找书学习相关 ...

  7. ADO.Net(三)——数据库操作类

    操作数据类 避免代码重用.造对象太多.不能分工开发 利用面向对象的方法,把数据访问的方式优化一下,利用封装类 一般封装成三个类: 1.数据连接类 提供数据连接对象 需要引用命名空间: using Sy ...

  8. 一个经典实用的iptables shell脚本

    PS:这个iptables脚本不错,很实用,根据实际应用改一下就可以自己用.分享出来,供大家来参考.原作者佚名.源代码如下: #!/bin/sh # modprobe ipt_MASQUERADE m ...

  9. spring annotation简述

    一.Annotation基本概念 Annotation是jdk5以后出现的新特性,在jdk中,其内置了许多自己的Annotation,例如@Override,@SuppresWarning,@Depr ...

  10. 【JSP】JSP基础学习记录(三)—— JSP的9个内置对象

    本节说一下JSP中的9个内置对象.这9个内置对象都是Servlet API接口的实例,只是JSP规范对他们进行了默认初始化(由JSP页面对应Servlet的_jspService()方法来创建这些实例 ...