题目

题目大意

给你一棵树,接下来对这棵树进行三种操作:

1、询问两点之间的距离。

2、让某个点变为它原来的第\(h\)个祖先的最后一个儿子。

3、求\(dfs\)序中最后一个深度为\(k\)的点。


正解

第一种是Cold_Chair大爷提出来的\(LCT\)维护\(ETT\)的做法。

具体怎样就不说了……据说代码5000+

第二种就直接是\(ETT\)了(其实这是一道ETT的板题啊)

对于入栈点(记作\(l\))打个\(+1\),对于出栈点(记作\(r\))打个\(-1\),维护前缀和。这个前缀和相当于深度。

这里维护前缀和的方法比较巧妙,不需要区间修改,具体见程序。

对于第一个操作,找到\(l_u\)和\(l_v\)之间最小的深度。显然这个深度就是它们的\(LCA\)的深度。

对于第二个操作,找第\(h\)个祖先的时候先求出祖先的深度,然后在前面找最靠右的深度为它的点。显然前缀和是连续的,所以可以在\(splay\)上二分。如果它是入栈点,就是要找的那个祖先;如果是出栈点,那它的父亲就是那个祖先。

对于第三个操作,直接找最后面前缀和为\(k\)的点。和操作二一样。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <climits>
#include <vector>
#define N 100010
#define INF 1000000000
int n,m;
vector<int> to[N];
struct Node *null,*root;
struct Node{
Node *fa,*c[2];
int val,sum,mx,mn;
inline void init(int _val){
fa=c[0]=c[1]=null;
val=sum=mx=mn=_val;
}
inline void update(){
sum=c[0]->sum+c[1]->sum+val;
mx=max(max(c[0]->mx,c[0]->sum+val+c[1]->mx),c[0]->sum+val);
mn=min(min(c[0]->mn,c[0]->sum+val+c[1]->mn),c[0]->sum+val);
}
inline bool getson(){return fa->c[0]!=this;}
inline void rotate(){
Node *y=fa,*z=y->fa;
if (z!=null)
z->c[y->getson()]=this;
bool k=getson();
fa=z;
y->c[k]=c[k^1],c[k^1]->fa=y;
c[k^1]=y,y->fa=this;
sum=y->sum,mx=y->mx,mn=y->mn;
y->update();
}
inline void splay(Node *t){
while (fa!=t){
if (fa->fa!=t)
getson()!=fa->getson()?rotate():fa->rotate();
rotate();
}
if (t==null)
root=this;
}
} in[N],out[N],*beg,*end;
inline Node *nxt(Node *t,bool dir){
t->splay(null);
Node *res=t->c[dir];
for (;res->c[dir^1]!=null;res=res->c[dir^1]);
return res;
}
inline void push_back(Node *x){
Node *t=root;
for (;t->c[1]!=null;t=t->c[1]);
t->splay(null);
t->c[1]=x,x->fa=t;
t->update();
}
inline Node *split(Node *l,Node *r){
l=nxt(l,0),r=nxt(r,1);
r->splay(null),l->splay(r);
Node *t=l->c[1];
l->c[1]=null,t->fa=null;
l->update(),r->update();
return t;
}
inline void insert(Node *t,Node *p){
p->splay(null);
Node *pre=nxt(p,0);
pre->splay(p);
pre->c[1]=t,t->fa=pre;
pre->update(),p->update();
}
inline Node *find_last(Node *t,int k){
t->splay(null);
Node *x=t->c[0],*res=null;
while (1){
if (x->c[1]!=null && x->c[1]->mn<=k-x->c[0]->sum-x->val && k-x->c[0]->sum-x->val<=x->c[1]->mx){
k-=x->c[0]->sum+x->val;
x=x->c[1];
continue;
}
else if (x->c[0]->sum+x->val==k)
return x;
x=x->c[0];
}
return res;
}
void dfs(int x){
in[x].init(1);
push_back(&in[x]);
for (int i=0;i<to[x].size();++i)
dfs(to[x][i]);
out[x].init(-1);
push_back(&out[x]);
}
int fa[N];
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i){
int num;
scanf("%d",&num);
for (int j=0;j<num;++j){
int x;
scanf("%d",&x);
to[i].push_back(x);
fa[x]=i;
}
}
null=new Node,*null={null,null,null,0,0,-INF,INF};
beg=new Node,beg->init(0),root=beg;
dfs(1);
end=new Node,end->init(0),push_back(end);
for (int i=1;i<=m;++i){
int op;
scanf("%d",&op);
if (op==1){
int u,v,depu,depv,deplca;
scanf("%d%d",&u,&v);
if (u==v){
printf("0\n");
continue;
}
in[u].splay(null),in[v].splay(&in[u]);
if (in[v].getson()==0)
swap(u,v);
Node *l=nxt(&in[u],0),*r=nxt(&in[v],1);
r->splay(null),l->splay(r);
deplca=l->c[0]->sum+l->val+l->c[1]->mn;
depu=l->c[0]->sum+l->val+1;
depv=l->sum;
printf("%d\n",depu+depv-deplca*2);
}
else if (op==2){
int v,h,anc;
scanf("%d%d",&v,&h);
in[v].splay(null);
Node *tmp=find_last(&in[v],in[v].c[0]->sum+1-h);
fa[v]=anc=(tmp->val==-1?fa[tmp-out]:tmp-in);
Node *t=split(&in[v],&out[v]);
insert(t,&out[anc]);
}
else{
int k;
scanf("%d",&k);
Node *tmp=find_last(end,k+1);
printf("%d\n",tmp->val==-1?fa[tmp-out]:tmp-in);
}
}
return 0;
}

总结

\(LCT\)搞不了的东西,要试试\(ETT\)。

[JZOJ3691] 【CF414E】Mashmokh's Designed tree的更多相关文章

  1. 【BZOJ2959】长跑(Link-Cut Tree,并查集)

    [BZOJ2959]长跑(Link-Cut Tree,并查集) 题面 BZOJ 题解 如果保证不出现环的话 妥妥的\(LCT\)傻逼题 现在可能会出现环 环有什么影响? 那就可以沿着环把所有点全部走一 ...

  2. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  3. 【BZOJ2816】【ZJOI2012】网络(Link-Cut Tree)

    [BZOJ2816][ZJOI2012]网络(Link-Cut Tree) 题面 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相 ...

  4. 【CF434E】Furukawa Nagisa's Tree 点分治

    [CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. 【SPOJ】QTREE7(Link-Cut Tree)

    [SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...

  7. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  8. 【BZOJ2870】最长道路tree 点分治+树状数组

    [BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...

  9. 【数据挖掘】分类之decision tree(转载)

    [数据挖掘]分类之decision tree. 1. ID3 算法 ID3 算法是一种典型的决策树(decision tree)算法,C4.5, CART都是在其基础上发展而来.决策树的叶子节点表示类 ...

随机推荐

  1. 基于Python玩转人工智能最火框架 TensorFlow应用实践✍✍✍

    基于Python玩转人工智能最火框架  TensorFlow应用实践 随着 TensorFlow 在研究及产品中的应用日益广泛,很多开发者及研究者都希望能深入学习这一深度学习框架.而在昨天机器之心发起 ...

  2. Django(十四)课程机构列表页数据展示,Django的modelform,关于urls的重新分发

    关于urls的重新分发: 如果所有url都配置在根路径的urls.py里,会特别多,而且也不易于修改,Django框架里支持urls的重新分发: 1.在根路径的urls配置上: PS:namespac ...

  3. js 万能判断

    console.log(Object.prototype.toString.call(123)) //[object Number] console.log(Object.prototype.toSt ...

  4. the blank final field factors may not have been initialized

    Q1: why we should initialize final field before completion of new instance? final means no changeabl ...

  5. 在 Keil uVision4 MDK下配置开发STM32F103Z完整教程

    转载的,请原作者勿怪,以下为原链接: http://www.51hei.com/bbs/dpj-30359-1.html(欢迎直接查看原作者) 环境搭建: 1.安装 Keil uVision4 MDK ...

  6. 将一个压缩文件分成多个压缩文件;RAR文件分卷

    有时候需要上传压缩文件,但是限制了单个文件的大小,那我们怎么才能将一个比较大的压缩文件分割成多个压缩文件,从而符合要求的进行文件的上传呢?这里小编告诉你一个技巧. 工具/原料 电脑 winrar(一般 ...

  7. c 语言函数分析

    第一个参数为指向线程标识符的指针. 第二个参数用来设置线程属性. 第三个参数是线程运行函数的起始地址. 最后一个参数是运行函数的参数. result = pthread_create(&tid ...

  8. webpack4.0基础

    安装 yarn add webpack webpack-cli -D npx webpack index.js 图片 file-loader module: { rules: [ { test: /\ ...

  9. 线程池 一 ScheduledThreadPoolExecutor

    java.util.concurrent public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ...

  10. Android Android Studio 如何导出 Jar 给 Unity 使用

    大致步骤如下: 1.创建新的 Android Studio 工程 2.为此 Android Studio 工程创建 Android Library 类库(也就是一个 Module)(后面就是用它生成 ...