博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P3979 遥远的国度
阅读量:6519 次
发布时间:2019-06-24

本文共 3190 字,大约阅读时间需要 10 分钟。

长者的题qwq

在没有换根之前,都是可以裸的树剖维护的

53knIz.png

一个最普通的询问

53kRT2.png

如果我们换一次根

就会变成一下情况

53l5gN.png

然而我们所查询的子树的结构并没有发生改变,为什么呢?

我们可以观察到,所查询的根并没有在当前的根到原来跟的路径上。

可以想象成你将所换的根提起来,在提的时候,所有结构发生改变的子树的根,都是所换根到原来根的路径上的节点,因为他们的子树中的节点要成为他们的父节点(or级别更高,不知道高到哪里去了

53k2fQ.png

就像上面一样

查询时就是查询红线以外的的节点

53kgJa.png]

看起来很简单的样子qwq,不就是如果查询节点的\(A\)和当前根节点的\(R\)\(Lca\)\(A\)的时候,就查询\(A\)的祖先and其祖先和\(A\)除了\(R\)所在的

子树,以外的所有节点么。

不过怎么查呢?

不要忘了这事一道树剖题,可以利用\(dfs\)序来进行

一颗子树中的\(dfs\)序是连续的

若一个节点\(A\)在一个以\(R\)为根的子树中
\(dfs\)序大于\(R\)\(dfs\)序,小于\(R\)\(dfs\)+\(R\)的子树大小。

所以我们可以枚举\(A\)的儿子,再根据上面这一条定理判断

然后如何使用树剖维护呢

还是根据一棵树中的\(dfs\)序是连续的来做。

如果我们将\(R\)所在的子树的链在线段树中都删去,那么剩下的链就是我们需要查询的区间。 所以我们只需要查询两次就可以了

#include
#include
#include
using std::swap;using std::min;const int maxn=101000;int n,m,r,now_r;struct node{ int p; int nxt;};node line[maxn<<1];int head[maxn],tail;void add(int a,int b){ line[++tail].p=b; line[tail].nxt=head[a]; head[a]=tail;}int dep[maxn],id[maxn],f[maxn],top[maxn];int son[maxn],size[maxn],num;int val[maxn],base[maxn];int t[maxn<<2],tag[maxn<<2];void build(int root,int l,int r){ if(l==r) { t[root]=base[l]; return ; } int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); t[root]=min(t[root<<1],t[root<<1|1]);}void push_down(int root,int l,int mid,int r){ if(!tag[root]) return ; int ls=root<<1,rs=root<<1|1; tag[ls]=tag[root]; tag[rs]=tag[root]; t[ls]=tag[root]; t[rs]=tag[root]; tag[root]=0; return ;}void updata(int root,int l,int r,int al,int ar,int val){ if(l>ar||r
=al&&r<=ar) { t[root]=val; tag[root]=val; return ; } int mid=(l+r)>>1; push_down(root,l,mid,r); updata(root<<1,l,mid,al,ar,val); updata(root<<1|1,mid+1,r,al,ar,val); t[root]=min(t[root<<1],t[root<<1|1]);}int query(int root,int l,int r,int al,int ar){ if(l>ar||r
=al&&r<=ar) return t[root]; int mid=(l+r)>>1; push_down(root,l,mid,r); return min(query(root<<1,l,mid,al,ar), query(root<<1|1,mid+1,r,al,ar));}/*----------------------------------------------------线段树*/void dfs1(int now,int fa,int d){ dep[now]=d; size[now]=1; f[now]=fa; int W=-1; for(int i=head[now];i;i=line[i].nxt) if(line[i].p!=fa) { dfs1(line[i].p,now,d+1); size[now]+=size[line[i].p]; if(size[line[i].p]>W) son[now]=line[i].p,W=size[line[i].p]; }}void dfs2(int now,int tf){ top[now]=tf; id[now]=++num; base[num]=val[now]; if(!son[now]) return ; dfs2(son[now],tf); for(int i=head[now];i;i=line[i].nxt) if(line[i].p!=f[now]&&line[i].p!=son[now]) dfs2(line[i].p,line[i].p); }void seg_updata(int a,int b,int c){ while(top[a]!=top[b]) { if(dep[top[a]]
dep[b]) swap(a,b); updata(1,1,num,id[a],id[b],c); return ;}int lca(int a,int b){ while(top[a]!=top[b]) { if(dep[top[a]]
=id[now_r]&&line[i].p!=f[a]) { S=line[i].p; break; }//使用规律进行查找,这里可以使用倍增加速 return min(query(1,1,num,1,id[S]-1),query(1,1,num,id[S]+size[S],num));//分成两段进行查询}int main(){ scanf("%d%d",&n,&m); int a,b,c; for(int i=1;i

转载于:https://www.cnblogs.com/Lance1ot/p/9390577.html

你可能感兴趣的文章
web.xml 中的listener、 filter、servlet 加载顺序
查看>>
MyBatis原理简介和小试牛刀
查看>>
js部分基础
查看>>
脏读,幻读,不可重复读解释和例子
查看>>
Tomcat指定(JDK路径)JAVA_HOME而不用环境变量
查看>>
Bluemix专属版本落地中国 开放物联网和认知计算能力
查看>>
汤姆大叔的6道javascript编程题题解
查看>>
【世界知名量子科学家加盟阿里】施尧耘出任阿里云量子技术首席科学家
查看>>
DataCore对外出售其虚拟化软件产品
查看>>
说说云计算与移动管理
查看>>
T-Mobile美国使用28GHz频段测试5G
查看>>
如何缓解影子云服务安全风险?
查看>>
Bossies 2016:最佳开源大数据工具
查看>>
银行卡信息安全事件频发 互联网站成数据泄露"重灾区"
查看>>
云服务器 ECS 使用OpenAPI管理ECS:使用OpenAPI弹性创建ECS实例
查看>>
象云2.0产品发布暨国产操作系统首次入驻公有云
查看>>
一个完美DCIM应该具备的功能与价值
查看>>
《SEO的艺术(原书第2版)》——1.5 人们如何搜索
查看>>
经验贴 | 电梯监控的布线技巧
查看>>
唐山联通与丰南区政府签署“智慧城市”战略合作协议
查看>>