题面

Description:

一棵\(n\)个点的树,每个点的初始权值为\(1\)。对于这棵树有\(q\)个操作,每个操作为以下四种操作之一:

  • + u v c:将\(u\)到\(v\)的路径上的点的权值都加上自然数\(c\);
  • - u1 v1 u2 v2:将树中原有的边\(u1-v1\)删除,加入一条新边\(u2-v2\),保证操作完之后仍然是一棵树;
  • * u v c:将\(u\)到\(v\)的路径上的点的权值都乘上自然数\(c\);
  • / u v:询问\(u\)到\(v\)的路径上的点的权值和,求出答案对于\(51061\)的余数。

Input

第一行两个整数\(n,q\)

接下来\(n-1\)行每行两个正整数\(u,v\),描述这棵树

接下来\(q\)行,每行描述一个操作

Output

对于每个/对应的答案输出一行

Sample Input

3 2

1 2

2 3

* 1 3 4

/ 1 1

Sample Output

4

HINT

100%的数据保证,$$1\le n,q\le 100000,1\le u,v,u1,v1,u2,v2\le n,0\le c\le 100001$$

Link-cut Tree 的作用&思想

  • 作用:类似于动态树链剖分(可以修改点、边)

  • 思想:用链的思想,把树剖为多个伸展树

    树与树之间只保存父关系,不保存子关系。

树链剖分把树分成若干条重链,对于每条重链,用线段树来维护信息。利用各线段树的信息来得到答案。

Link-cut Tree 的基本操作

1.access(u):把u到根节点变成一条链





u是当前点,v是前驱

其实就是一层一层往上爬,每次顺带修改链上的儿子

void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u);
ch[u][1]=v;
pushup(u);
}
}

2.makeroot(u):把u变成根



access+splay后,u已经是根,可splay的路径上需要进行父子反向,其他的没有影响,因此要进行翻转

void makeroot(int u){
access(u);
splay(u);
reverse(u);
}

3.cut(u,v):切断u,v之间的连接



我们先makeroot(u)+access(v)+splay(v)

由于u和v同在一棵Splay中且u一定是v的父亲,所以Splay中v的左儿子一定是u,断开即可。

void cut(int a,int b){
makeroot(a);
access(b);
splay(b);
ch[b][0]=0;
fa[a]=0;
pushup(b);
}

4.link(u,v):连接u,v



把u变成根,这时u没有父亲,就可以安心连接了。再把其父亲设为v,就实现了连接。

void link(int a,int b){
makeroot(a);
fa[a]=b;
}

5.isconnect(u,v):检测u,v是否连接



我们先makeroot(u)+access(v)+splay(v)

如果u和v不在同一棵LCT中,执行makeroot(u)后,u的父亲应该为空(他是根)

除非a和b在同一棵树中,在access(v)+splay(v)后,u与v应该在同一棵Splay中,既然v是根,那么u就不是根,即u一定有一个父亲存在。

bool isconnect(int a,int b){
if(a==b) return true;
makeroot(a);
access(b);
splay(b);
return fa[a];
}

代码

注意有多个修改中懒标的特殊处理方式。

#include<iostream>
#include<cstdio>
using namespace std;
int ch[100001][2],fa[100001],siz[100001],lazr[100001],cnt,n,q;
unsigned num[100001],tot[100001],lazp[100001],lazc[100001],mod=51061;
inline unsigned rd(){
unsigned re=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
re=re*10+ch-'0';
ch=getchar();
}
return re;
}
inline bool isroot(int bt){return ch[fa[bt]][0]!=bt&&ch[fa[bt]][1]!=bt;}
inline int drct(int bt){return ch[fa[bt]][1]==bt;}
inline void pushup(int bt){siz[bt]=siz[ch[bt][0]]+siz[ch[bt][1]]+1;tot[bt]=((tot[ch[bt][0]]+num[bt])%mod+tot[ch[bt][1]])%mod;}
inline void reverse(int bt){swap(ch[bt][0],ch[bt][1]);lazr[bt]^=1;}
inline void add(int bt,unsigned c){num[bt]=(num[bt]+c)%mod;tot[bt]=(tot[bt]+siz[bt]*c)%mod;lazp[bt]=(lazp[bt]+c)%mod;}
inline void times(int bt,unsigned c){num[bt]=(num[bt]*c)%mod;tot[bt]=(tot[bt]*c)%mod;lazc[bt]=(lazc[bt]*c)%mod;lazp[bt]=(lazp[bt]*c)%mod;}
inline void pd(int bt){
if(lazr[bt]){
if(ch[bt][0])reverse(ch[bt][0]);
if(ch[bt][1])reverse(ch[bt][1]);
lazr[bt]=0;
}
if(lazp[bt]){
if(ch[bt][0])add(ch[bt][0],lazp[bt]);
if(ch[bt][1])add(ch[bt][1],lazp[bt]);
lazp[bt]=0;
}
if(lazc[bt]!=1){
if(ch[bt][0])times(ch[bt][0],lazc[bt]);
if(ch[bt][1])times(ch[bt][1],lazc[bt]);
lazc[bt]=1;
}
}
inline void pushdown(int u){
if(!isroot(u))pushdown(fa[u]);
pd(u);
}
inline void rotate(int u){
int f=fa[u],g=fa[f],c=drct(u);
if(!isroot(f))ch[g][drct(f)]=u;
fa[u]=g;
ch[f][c]=ch[u][c^1];
if(ch[f][c])fa[ch[f][c]]=f;
ch[u][c^1]=f;
fa[f]=u;
pushup(f);
pushup(u);
}
void splay(int u){
pushdown(u);
while(!isroot(u)){
if(!isroot(fa[u]))rotate(drct(fa[u])==drct(u)?fa[u]:u);
rotate(u);
}
}
void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u);
ch[u][1]=v;
pushup(u);
}
}
void makeroot(int u){
access(u);
splay(u);
reverse(u);
}
void link(int a,int b){
makeroot(a);
fa[a]=b;
}
void cut(int a,int b){
makeroot(a);
access(b);
splay(b);
ch[b][0]=0;
fa[a]=0;
pushup(b);
}
void makeline(int u,int v){
makeroot(u);
access(v);
splay(v);
}
int main(){
n=rd();
q=rd();
for(int i=1;i<=n;i++)lazc[i]=num[i]=tot[i]=siz[i]=1;
for(int i=1;i<n;i++){
int u=rd(),v=rd();
link(u,v);
}
makeroot(1);
for(int i=1;i<=q;i++){
char cha[5];
scanf("%s",cha);
int u=rd(),v=rd();
if(cha[0]=='+'){
unsigned c=rd();
makeline(u,v);
add(v,c);
}else if(cha[0]=='-'){
int u2=rd(),v2=rd();
cut(u,v);
link(u2,v2);
}else if(cha[0]=='*'){
unsigned c=rd();
makeline(u,v);
times(v,c);
}else if(cha[0]=='/'){
makeline(u,v);
printf("%u\n",tot[v]);
}
}
}

[Link-Cut-Tree][BZOJ2631]Tree的更多相关文章

  1. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  2. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

  3. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  4. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  5. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  6. bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

    link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...

  7. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  8. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  9. [CodeForces - 614A] A - Link/Cut Tree

    A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...

  10. Link Cut Tree 总结

    Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...

随机推荐

  1. input type="file"获取文件名方法

    文件上传比较丑,样式调整时会有一个获取文件名,或者包含文件路径的文件名的方法 html代码 <div class="file-box"> <form id=&qu ...

  2. (一)JavaScript之[数据类型]与[对象]

    1].数据类型字符串(String).数字(Number).布尔(Boolean).数组(Array).对象(Object).空(Null).未定义 (Undefined). //极大或极小的数字可以 ...

  3. iDempiere 使用指南 生产插件(Manufacturing)安装过程

    Created by 蓝色布鲁斯,QQ32876341,blog http://www.cnblogs.com/zzyan/ iDempiere官方中文wiki主页 http://wiki.idemp ...

  4. 使用UserLock如何实现工作站登陆访问限制

    UserLock允许用户限制受保护账户可登陆的工作站/终端.工作站/终端限制可以通过设置或者使用特定的IP范围,计算机名/IP或组织单位实现. 对于每个工作站限制你需要指定所要限制的会话类型(默认情况 ...

  5. 用Android studio进行 OpenCV 开发的第一个项目

    我的天! 折腾了好久终于搭建成功了第一个项目. 项目环境: Windows 7  家庭普通版  64位 Android studio 1.5.1 OpenCV-2.4.9-android-sdk 基于 ...

  6. Web前端开发规范(二)

    3.HTML代码规范 .html文件必须存放在项目工程约定的目录中. .html文件的命名:以模块 + 功能的结合方式来命名,比如:newsList.html. 文档类型声明:HTML4中使用< ...

  7. XCode 如何真机运行别人的demo项目

    iOS应用安装到真机需要证书和mobileprovision 文件,拿到别人的项目 是没有这些的 ,也就运行不起来. 要想运行起来, 需要选中项目,  target - > 修改 bundlei ...

  8. 从C++起步到MFC实战VC++软件工程师高端培训 视频保存在 播音员的网盘中

    从C++起步到MFC实战VC++软件工程师高端培训(服务器端开发方向)[共332课时]视频保存在 播音员的网盘中http://www.it1352.com/VideoTutorial/Details? ...

  9. MVC学习笔记:MVC实现用户登录验证ActionFilterAttribute用法并实现统一授权

    在项目下新建一个文件夹来专门放过滤器类,首先创建一个类LoginFilter,这个类继承ActionFilterAttribute.用来检查用户是否登录和用户权限.: using System; us ...

  10. Windows服务程序时钟调用

    1       大概思路 设计服务程序 创建服务 安装必备组件 编写Service1 运行效果 2       设计服务程序 创建服务程序,通过添加System.Timers时钟进行定时向Wecome ...