最近沉迷码农题无法自拔

首先有一个暴力的想法:对于每个重链维护一个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. 蓝色科技AE宣传片头光晕视频

    蓝色科技AE宣传片头光晕视频素材,蓝色AE炫光素材,科技AE片头,精美,AE特效,绚丽,AE模板,视频素材,动画. 地址:http://www.huiyi8.com/xuanguang/ae/

  2. rust borrow and move

    extern crate core; #[deriving(Show)] struct Foo { f : Box<int> } fn main(){ let mut a = Foo {f ...

  3. linux 进程学习笔记-进程pipe管道

    所谓“进程间通信(IPC,inter-process communication)”,按照其目的讲就是让进程之间能够“共享数据”,“传输数据”,“事件通知”等,我所知道的一共有“管道” “信号” “消 ...

  4. MySQL当月负毛利订单明细_20161027

    #当月每天负毛利订单明细 SELECT c.ID,a.city AS 城市,a.username AS 用户ID,a.订单日期,a.订单号,a.销售确认额,a.成本额,a.毛利1, CASE THEN ...

  5. plsql developer点滴

    PLSql中查看编译错误的具体内容: 1. 打开Command Windows show errors procedure procedure_name 

  6. docker安装与操作

    准备和安装 1.到这个路径下下载docker engine: https://get.docker.com/rpm/1.7.1/centos-7/RPMS/x86_64/docker-engine-1 ...

  7. Hive操作笔记

    hive库清表,删除数据 insert overwrite table lorry.bigdata select * from lorry.bigdata where 1=0 hive的simple模 ...

  8. poj2392磊石头——排序后背包

    题目: 首先按限制高度从小到大排序,不会影响可行解,而不排序可能卡掉正确的情况: 用%2滚动数组时一定注意每次复制上一种情况,因为这个WA了好几次. 代码如下: #include<iostrea ...

  9. C++多态的实现条件

    #include <iostream> class Person{ public: virtual void say(){ std::cout<<"person&qu ...

  10. css3 实现运动动画 圆与椭圆

    圆: html <div class="demo4"><div></div></div> css .demo4{ width: 20 ...