最近沉迷码农题无法自拔

首先有一个暴力的想法:对于每个重链维护一个splay,需要翻转的连起来,翻转,接回去

然后发现这样没问题。。。

一条链只能跨log个重链,也就只有log个splay的子树参与重排,所以一次翻转只要log^2的时间

需要维护的东西有点多

头一次在splay上维护这么多乱七八糟的东西,写错了好几遍

感觉学到不少debug技巧,也纠正了之前splay写法的一个小漏洞

话说极限数据好像和miaom拍不过啊。。。但是我们都A了啊

好烦啊不知道谁出锅了

 #include <bits/stdc++.h>
#define num(x) (dep[x]-dep[top[x]]+1)
#define ans tr[split(num(x),num(y))]
#define rt root[RT]
#define RT1 root[n+1]
#define NO 800000
#define N 800000
#define INF 2000000000
#define ll long long
using namespace std;
struct trnode
{
int size,min,max;ll sum;int plus,num;
bool rev;
trnode()
{
size=;min=max=sum=plus=rev=num=;
}
} tr[NO];
int n,m,R,p,q,RT,x,y,z,RET,E,NODE,sttop,inv_x,inv_y;ll ret;
int c[NO][],fa[NO];bool die[N];
int root[N],Fa[N],size[N],fir[N],top[N],dep[N],st[N],sz[N],lin[N];
int nex[*N],to[*N];
char cmd[];
void up(int x)
{
if(!x)
{
tr[]=trnode();tr[].size=;
return;
}
tr[x].size=tr[c[x][]].size+tr[c[x][]].size+;
tr[x].sum=tr[c[x][]].sum+tr[c[x][]].sum+(ll)tr[x].plus*tr[x].size+tr[x].num;
tr[x].max=max(tr[c[x][]].max,tr[c[x][]].max)+tr[x].plus;
tr[x].max=max(tr[x].max,tr[x].num+tr[x].plus);
tr[x].min=tr[x].num;
if(c[x][]!=)
tr[x].min=min(tr[x].min,tr[c[x][]].min);
if(c[x][]!=)
tr[x].min=min(tr[x].min,tr[c[x][]].min);
tr[x].min+=tr[x].plus;
}
void down(int x)
{
if(tr[x].rev)
swap(c[x][],c[x][]),tr[c[x][]].rev^=,tr[c[x][]].rev^=,tr[x].rev=;
if(tr[x].plus)
tr[c[x][]].plus+=tr[x].plus,tr[c[x][]].plus+=tr[x].plus,
tr[x].num+=tr[x].plus,tr[x].plus=,up(c[x][]),up(c[x][]);
}
void rot(int x)
{
down(fa[x]);down(x);
int y=fa[x],k=c[y][]==x;
if(fa[y]) c[fa[y]][c[fa[y]][]==y]=x;
else rt=x;
fa[x]=fa[y];fa[y]=x;
c[y][k]=c[x][!k];
if(c[x][!k])
fa[c[x][!k]]=y;
c[x][!k]=y;
up(y);up(x);
}
void splay(int x,int z)
{
for(int y;(y=fa[x])!=z;rot(x))
if(fa[y]!=z)
rot(c[fa[y]][]==y^c[y][]==x?x:y);
}
int Find(int x)
{
if(x==) return -;
if(x>tr[rt].size) return -;
int now=rt;
while(down(now),tr[c[now][]].size+!=x)
if(x<=tr[c[now][]].size)
now=c[now][];
else
x-=tr[c[now][]].size+,now=c[now][];
return now;
}
int split(int x,int y)
{
if(x== && y==tr[rt].size)
return rt;
if(x==)
{ splay(Find(y+),);return c[rt][];}
if(y==tr[rt].size)
{ splay(Find(x-),);return c[rt][];}
splay(Find(x-),);
splay(Find(y+),rt);
return c[c[rt][]][];
}
void upd(int x)
{
int len=;
while(x)
lin[++len]=x,x=fa[x];
for(int i=len;i;i--)
down(lin[i]);
for(int i=;i<=len;i++)
up(lin[i]);
}
int Split(int x,int y)
{
int p=split(x,y),q=fa[p];
upd(p);
fa[p]=;c[q][c[q][]==p]=;
upd(q);
splay(q,);
return p;
}
void work(int x,int y)
{
RT=top[x];int tem;
if(cmd[]=='c')
tr[tem=split(num(x),num(y))].plus+=z,upd(tem);//?
if(cmd[]=='S')
ret+=ans.sum;
if(cmd[]=='a') ret=max(ret,(ll)ans.max);
if(cmd[]=='i') RET=min(RET,ans.min);
if(cmd[]=='v')
{
int tem=Split(num(x),num(y));
if(tem==rt) die[RT]=;
RT=n+;
if(!rt) rt=tem;
else
{
splay(Find(),);
c[rt][]=tem;fa[tem]=rt;
splay(tem,);
}
}
}
void add(int p,int q)
{
to[++E]=q;nex[E]=fir[p];fir[p]=E;
}
int build(int now,int fat)
{
size[now]=;Fa[now]=fat;dep[now]=dep[fat]+;
for(int i=fir[now];i;i=nex[i])
if(to[i]!=fat)
size[now]+=build(to[i],now);
return size[now];
}
void ins()
{
int now=rt;
while(c[now][]) now=c[now][];
c[now][]=++NODE;fa[NODE]=now;
tr[NODE]=trnode();
splay(NODE,);
}
void pou(int now,int Top)
{
top[now]=Top;
if(Top==now)
tr[++NODE]=trnode(),root[now]=NODE;
else
RT=Top,ins();
int id=;
for(int i=fir[now];i;i=nex[i])
if(to[i]!=Fa[now])
if(size[to[i]]>size[id])
id=to[i];
if(id) pou(id,Top);
for(int i=fir[now];i;i=nex[i])
if(to[i]!=Fa[now] && to[i]!=id)
pou(to[i],to[i]);
}
int main()
{
scanf("%d%d%d",&n,&m,&R);
for(int i=;i<n;i++)
scanf("%d%d",&p,&q),
add(p,q),add(q,p);
tr[].size=;
build(R,);
pou(R,R);
for(int i=;i<=m;i++)
{
if(i==)
int e=;
scanf("%s%d%d",cmd,&x,&y);
if(cmd[]=='c') scanf("%d",&z);
ret=;RET=INF;sttop=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
work(top[x],x);
st[++sttop]=top[x];sz[sttop]=num(x);
x=Fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(cmd[]=='v')
{
RT=top[x];
inv_x=Find(num(x)-);inv_y=Find(num(y)+);
}
work(x,y);
if(cmd[]=='S' || cmd[]=='a') printf("%lld\n",ret);
if(cmd[]=='i') printf("%d\n",RET);
if(cmd[]=='v')
{
RT=n+;
tr[rt].rev^=;
int tem=Split(,num(y)-num(x)+);
RT=top[x];
if(inv_x==- && inv_y==-)
rt=tem,die[RT]=;
else
if(inv_x==-)
{
splay(inv_y,);
c[rt][]=tem;fa[tem]=rt;
splay(tem,);
}
else
if(inv_y==-)
splay(inv_x,),c[rt][]=tem,fa[tem]=rt,splay(tem,);
else
splay(inv_x,),splay(inv_y,rt),c[c[rt][]][]=tem,fa[tem]=c[rt][],splay(tem,);
for(int i=sttop;i;i--)
{
RT=n+;
int tem=Split(,sz[i]);
RT=st[i];
if(die[RT]) die[RT]=,rt=tem;
else
{
splay(Find(),);
c[rt][]=tem;fa[tem]=rt;splay(tem,);
}
}
}
root[n+]=;die[n+]=;
}
return ;
}

bzoj3159决战 码农题 树剖套splay的更多相关文章

  1. 【小技巧】树剖套线段树优化建图如何做到 O(nlogn)

    前提:用树剖套线段树优化树链连边.例题:bzoj4699 我们说树剖的时间复杂度是 $O(n\times log(n))$,是因为访问一条链时需要经过 $log(n)$ 级别条重链,对于每条重链还需要 ...

  2. codechef FIBTREE 码农题 线段树 树剖 标记永久化

    好烦啊,调了半天 线段树部分标记比较多,手抖打错了一个 剩下的都是取模的问题 我自己瞎jb推的公式里保留了abs,但是在模意义下是gg的,所以必须把正负区分开 调试的时候一定要注意构造各种形状的树,不 ...

  3. BZOJ 2157 旅行(树链剖分码农题)

    写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...

  4. 洛谷P4315 月下“毛景树”(树剖+线段树)

    传送门 woc这该死的码农题…… 把每一条边转化为它连接的两点中深度较深的那一个,然后就可以用树剖+线段树对路径进行修改了 然后顺便注意在上面这种转化之后,树剖的时候不能搞$LCA$ 然后是几个注意点 ...

  5. 洛谷P1505 [国家集训队]旅游(树剖+线段树)

    传送门 这该死的码农题…… 把每一条边变为它连接的两个点中深度较浅的那一个,然后就是一堆单点修改/路径查询,不讲了 这里就讲一下怎么搞路径取反,只要打一个标记就好了,然后把区间和取反,最大最小值交换然 ...

  6. 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)

    传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...

  7. 【BZOJ 3196】二逼平衡树 线段树套splay 模板题

    我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...

  8. P4175 [CTSC2008]网络管理 树剖+树套树

    $ \color{#0066ff}{ 题目描述 }$ M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通 ...

  9. 洛谷树剖模板题 P3384 | 树链剖分

    原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...

随机推荐

  1. 分享知识-快乐自己:SpringMVC 底层执行原理解析

    底层实现原理图: 观看底层代码: 1):打开 web.xml 文件  2):按住 Ctrl + 鼠标左键 进入底层查看源码   3):按住 Ctrl+o 找到对应的方法doDispatch   5): ...

  2. 迁移学习——使用Tensorflow和VGG16预训模型进行预测

    使用Tensorflow和VGG16预训模型进行预测 from:https://zhuanlan.zhihu.com/p/28997549   fast.ai的入门教程中使用了kaggle: dogs ...

  3. Linux下查找进程,kill进程

    1. ps命令用来查找linux运行的进程,常用命令: ps aux | grep 进程名:  eg:ps aux | grep admin 查找admin的进程 或者 ps -ef | grep j ...

  4. 写个sleep玩玩

    static void sig_when_weakup(int no){ printf("weakup weakup\n"); longjmp(buf, ); } void wea ...

  5. hdu-1542 Atlantis(离散化+线段树+扫描线算法)

    题目链接: Atlantis Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/32768 K (Java/Others) ...

  6. python程序打包工具 ── cx_Freeze

    cx_Freeze是一个类似py2exe的工具,它们区别是py2exe是将python程序打包成windows下可以执行的exe文件的,而cx_Freeze则是将python程序打包为linux下可以 ...

  7. ubuntu关闭cups服务

    本人使用的ubuntu10.10每次开机时使用nmap扫描127.0.0.1的时候总是能发现一个631端口开启,在/etc/services找到 631端口是网络打印机服务,但对于我一个普通用户来说这 ...

  8. django-crontab 定时执行任务方法

    需求 每天请求一封邮件,并读取该邮件 这个其实可以使用linux 自带了crontab实现,但是毕竟是django 开发.想着不知道有没有方法可以从django 中实现. 简单搜索了下,这方面的方法确 ...

  9. uC/OS-II源码分析(六)

    μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个.确定哪个任务优先级最高, 下面该哪个任务运行了的工作是由调度器(Scheduler)完成的.任务级的调度是由函数 OSSched()完成的.中 ...

  10. 树——平衡二叉树插入和查找的JAVA实现

    package com.tomsnail.data.tree; /** * AVL二叉平衡树 * @author tomsnail * @date 2015年3月30日 下午4:35:50 */ pu ...