QAQ 237行的代码 QAQ
打了我一个下午啊啊啊啊。
题目
我的做法
基础做法
机房大佬CLB提示我这道题目是虚树(当然我的做法不知道是不是虚树,反正虚就对了),于是我发现对于以下的图:
在对外显示上,两个蓝点的LCA是可以代替这两个蓝点的,然后,我们的做法出来了,对于两个点,维护他们两个的LCA,如果一个虚点(即不是真的异象石的位置)只有一个点(不管实的虚的),那么就将这个点连到其父亲上面。
特别的,因为(个人觉得)难以维护目前树上没有父亲的点,所以默认 1 1 1点永远存在。(当然后来发现没有父亲的点最多一个,其实用个 r o o t root root存一下就行了)
当然,还是有不少细节的。
给上一个图(绿色为虚点,蓝色为实点,黑色为原树上的边,红色为虚树上的边):
注:一下内容的儿子、父亲、LCA可能有点难分辨是实树上的还是虚树上的,同时以下都以插入为例。
如何在log时间内查询一个点最近的父亲?
处理出DFS序后,我们新建了一个点,那么对于这个这个新建的点,如果是叶子节点的,那么整个子树(实树)直接认为其是父亲(用线段树实现),但是如果是非叶子节点,可以发现,他建立时最多只有两个儿子(虚树)节点(因为我们只要两个点有了LCA(实树)就建),然后把DFS序分成两段即可,但是需要注意的是,不一定是两个儿子,有时候只有一个儿子,因为LCA可能是其自己。
如何在log的时间内查询一个点的某个儿子的子树内的儿子节点编号
首先一个点的一个儿子(原树)的子树内的只可能存在一个儿子(虚树),两个的话他们必然会产生一个LCA,那么怎么查到这个点就是重中之重的事了,由于实树儿子的编号是固定的,我们可以在这个点的平衡树中插入其儿子的编号,而附加权值就是这个儿子子树中的虚树儿子编号。
实现
由于 1 1 1一直都在,所以 z a n s zans zans表示到 1 1 1点的距离,根据要不要经过 1 1 1决定加还是不加。(本人觉得 r o o t root root的实现会更简单吧)
当然只有亿点细节。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),以及亿点点的常数,但也许是因为平衡树跑不满,或者因为正解用了set的缘故,我跑的竟然比正解快???
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define N 110000
#define M 210000
using namespace std;
typedef long long LL;
//FHQ treap(平衡树)
int val[M],ke1[M],ke2[M],tot,rt[M],siz[N],son[M][2];bool li[N]/*这个点是否已经存在异象石*/;//最上层的点全部归到1
void spilt(int now,int k,int &A,int &B)
{
if(!now)A=B=0;
else
{
if(ke1[now]<=k)A=now,spilt(son[A][1],k,son[A][1],B);
else B=now,spilt(son[B][0],k,A,son[B][0]);
}
}
int mer(int A,int B)
{
if(!A || !B)return A+B;
if(val[A]<=val[B])son[A][1]=mer(son[A][1],B);
else son[B][0]=mer(A,son[B][0]),A^=B^=A^=B;
return A;
}
inline void add(int id,int k1,int k2)
{
tot++;val[tot]=rand();ke1[tot]=k1;ke2[tot]=k2;
int x,y;spilt(rt[id],k1,x,y);
rt[id]=mer(mer(x,tot),y);
}
inline void del(int id,int k)
{
int x,y,z;spilt(rt[id],k,x,z);spilt(x,k-1,x,y);
rt[id]=mer(x,z);
}
inline void change(int id,int k1,int k2)
{
int x,y,z;spilt(rt[id],k1,x,z);spilt(x,k1-1,x,y);
ke2[y]=k2;
rt[id]=mer(x,mer(y,z));
}
inline int findz(int id,int k)//这个子树是否存在虚树的儿子
{
int bk=0;
int x,y,z;spilt(rt[id],k-1,x,y);spilt(y,k,y,z);
if(y)bk=ke2[y];
rt[id]=mer(mer(x,y),z);
return bk;
}
//线段树
struct TREE
{
int l,r,c;
}tr[M];int tlen;
void bt(int l,int r)
{
int now=+