• Link-Cut-Tree 的懒标记下传正确食用方法。

我们来逐步分析每一个操作。


1:+ u v c:将u到v的路径上的点的权值都加上自然数c;

  • 解决方法:

  • 很显然,我们可以 split(u,v) 来提取u,v这一段区间,提取完了将 Splay(v),然后直接在v上打加法标记add即可。

  • 代码:

inline void pushadd(ll x,ll val){//打标记
s[x]+=sz[x]*val,v[x]+=val,add[x]+=val;
s[x]%=MOD,v[x]%=MOD,add[x]%=MOD;
} inline void split(ll x,ll y){//LCT基本操作split,不再赘述
makeroot(x);Access(y);Splay(y);
} //(main函数中):
if(op[0]=='+'){
scanf("%lld%lld%lld",&x,&y,&v);//输入信息
split(x,y);pushadd(y,v);//提取链条&打标记
}

2:- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;

  • 解决方法:

  • 删除边即cut操作,加边即link操作。

  • 代码:

inline void link(ll x,ll y){
makeroot(x);if(findroot(x)!=y)f[x]=y;
}
inline void cut(ll x,ll y){
makeroot(x);split(x,y);
if(findroot(y)==x&&f[x]==y&&!ch[x][1])
f[x]=ch[y][0]=0;return;
}//LCT基本操作link&cut,不再赘述 //(main函数中):
if(op[0]=='-'){
scanf("%lld%lld",&x,&y);cut(x,y);//删边
scanf("%lld%lld",&x,&y);link(x,y);//加边
}

3:* u v c:将u到v的路径上的点的权值都乘上自然数c;

  • 解决方法:

  • 很显然,我们可以split(u,v)来提取u,v这一段区间,提取完了将Splay(v),然后直接在v上打乘法标记mul即可。(跟第一个操作基本同理)

  • 代码:

inline void pushmul(ll x,ll val){//打标记
s[x]*=val,v[x]*=val,mul[x]*=val,add[x]*=val;
s[x]%=MOD,v[x]%=MOD,mul[x]%=MOD,add[x]%=MOD;
} //(main函数中):
if(op[0]=='*'){
scanf("%lld%lld%lld",&x,&y,&v);
split(x,y);pushmul(y,v);
}

4:/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

  • 解决方法:

  • 我们可以像第1、3操作那样,先扯出这条链来(split(u,v)),因为split操作时最后Splay过了,根节点是v。而Splay的时候又将整棵Splay上的节点信息都跟新好了(懒标记都下传了),所以这棵Splay的根节点的点权即为这课Splay的点权和。而这课Splay又代表着u,v这一段区间,所以最后只需输出s[v]即可。

  • 代码:

//(main函数中):
if(op[0]=='/'){
scanf("%lld%lld",&x,&y);
split(x,y);printf("%lld\n",s[y]);
}

Code:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define RI register ll
#define A printf("A")
#define C printf(" ")
#define MOD 51061
using namespace std;
const ll N=1e5+2;
template<typename _Tp> inline void IN(_Tp& dig){
char c;bool flag=0;dig=0;
while(c=getchar(),!isdigit(c))if(c=='-')flag=1;
while(isdigit(c))dig=dig*10+c-'0',c=getchar();
if(flag)dig=-dig;
}ll f[N],s[N],v[N],sz[N],rev[N],mul[N],add[N],hep[N],ch[N][2];
inline ll get(ll x){return ch[f[x]][0]==x||ch[f[x]][1]==x;}
inline ll chk(ll x){return ch[f[x]][1]==x;}
inline void pushfilp(ll x){
swap(ch[x][0],ch[x][1]);rev[x]^=1;
}
inline void pushup(ll x){
s[x]=(s[ch[x][0]]+s[ch[x][1]]+v[x])%MOD;
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
}
inline void pushmul(ll x,ll val){
s[x]*=val,v[x]*=val,mul[x]*=val,add[x]*=val;
s[x]%=MOD,v[x]%=MOD,mul[x]%=MOD,add[x]%=MOD;
}
inline void pushadd(ll x,ll val){
s[x]+=sz[x]*val,v[x]+=val,add[x]+=val;
s[x]%=MOD,v[x]%=MOD,add[x]%=MOD;
}
inline void pushdown(ll x){
if(mul[x]!=1)pushmul(ch[x][0],mul[x]),pushmul(ch[x][1],mul[x]);
if(add[x])pushadd(ch[x][0],add[x]),pushadd(ch[x][1],add[x]);
if(rev[x]){
if(ch[x][0])pushfilp(ch[x][0]);
if(ch[x][1])pushfilp(ch[x][1]);
}rev[x]=0,add[x]=0,mul[x]=1;return;
}
inline void rotate(ll x){
ll y=f[x],z=f[y],k=chk(x),v=ch[x][!k];
if(get(y))ch[z][chk(y)]=x;ch[x][!k]=y,ch[y][k]=v;
if(v)f[v]=y;f[y]=x,f[x]=z;pushup(y),pushup(x);
}
inline void Splay(ll x){
ll y=x,top=0;hep[++top]=y;
while(get(y))hep[++top]=y=f[y];
while(top)pushdown(hep[top--]);
while(get(x)){
y=f[x],top=f[y];
if(get(y))rotate((ch[y][0]==x)^(ch[top][0]==y)?y:x);
rotate(x);
}pushup(x);return;
}
inline void Access(ll x){
for(register ll y=0;x;x=f[y=x])
Splay(x),ch[x][1]=y,pushup(x);
}
inline ll findroot(ll x){
Access(x);Splay(x);
while(ch[x][0])pushdown(x),x=ch[x][0];
return x;
}
inline void makeroot(ll x){
Access(x);Splay(x);pushfilp(x);
}
inline void split(ll x,ll y){
makeroot(x);Access(y);Splay(y);
}
inline void link(ll x,ll y){
makeroot(x);if(findroot(x)!=y)f[x]=y;
}
inline void cut(ll x,ll y){
makeroot(x);split(x,y);
if(findroot(y)==x&&f[x]==y&&!ch[x][1])
f[x]=ch[y][0]=0;return;
}char op[2];
int main(){
ll n,m,x,y;scanf("%lld%lld",&n,&m);
for(register int i=1;i<=n;++i)
mul[i]=sz[i]=v[i]=1;ll v;
for(register int i=1;i<n;++i)
scanf("%lld%lld",&x,&y),link(x,y);
for(register int i=1;i<=m;++i){
scanf("%s",op);
if(op[0]=='+'){
scanf("%lld%lld%lld",&x,&y,&v);
split(x,y);pushadd(y,v);
}else if(op[0]=='-'){
scanf("%lld%lld",&x,&y);cut(x,y);
scanf("%lld%lld",&x,&y);link(x,y);
}else if(op[0]=='*'){
scanf("%lld%lld%lld",&x,&y,&v);
split(x,y);pushmul(y,v);
}else if(op[0]=='/'){
scanf("%lld%lld",&x,&y);
split(x,y);printf("%lld\n",s[y]);
}
}return 0;
}

因为51061 * 5106是会越过int界限的,所以我开的longlong(当然也可以开无符号int)

我居然因为没开longlong调了两个多小时.....

题解 洛谷P1501/BZOJ2631【[国家集训队]Tree II】的更多相关文章

  1. 【洛谷 P1501】 [国家集训队]Tree II(LCT)

    题目链接 Tree Ⅱ\(=\)[模板]LCT+[模板]线段树2.. 分别维护3个标记,乘的时候要把加法标记也乘上. 还有就是模数的平方刚好爆\(int\),所以开昂赛德\(int\)就可以了. 我把 ...

  2. 【洛谷1501】[国家集训队] Tree II(LCT维护懒惰标记)

    点此看题面 大致题意: 有一棵初始边权全为\(1\)的树,四种操作:将两点间路径边权都加上一个数,删一条边.加一条新边,将两点间路径边权都加上一个数,询问两点间路径权值和. 序列版 这道题有一个序列版 ...

  3. 洛谷 P1501 [国家集训队]Tree II 解题报告

    P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...

  4. P1501 [国家集训队]Tree II(LCT)

    P1501 [国家集训队]Tree II 看着维护吧2333333 操作和维护区间加.乘线段树挺像的 进行修改操作时不要忘记吧每个点的点权$v[i]$也处理掉 还有就是$51061^2=2607225 ...

  5. BZOJ 2631 [国家集训队]Tree II (LCT)

    题目大意:给你一棵树,让你维护一个数据结构,支持 边的断,连 树链上所有点点权加上某个值 树链上所有点点权乘上某个值 求树链所有点点权和 (辣鸡bzoj又是土豪题,洛谷P1501传送门) LCT裸题, ...

  6. 洛谷P1501 [国家集训队]Tree II(LCT,Splay)

    洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...

  7. ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】

    题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...

  8. 树链剖分【洛谷P1505】 [国家集训队]旅游

    P1505 [国家集训队]旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城 ...

  9. 【洛谷】P4555 [国家集训队]最长双回文串

    P4555 [国家集训队]最长双回文串 题源:https://www.luogu.com.cn/problem/P4555 原理:Manacher 还真比KMP好理解 解决最长回文串问题 转化为长度为 ...

随机推荐

  1. YTU 2507: 李白打酒

    2507: 李白打酒 时间限制: 1 Sec  内存限制: 128 MB 提交: 414  解决: 186 题目描述 话说大诗人李白,一生好饮.幸好他从不开车.  一天,他提着酒壶,从家里出来,酒壶中 ...

  2. python-----利用filecmp删除重复文件

    以下代码素材自取:链接:https://pan.baidu.com/s/1fL17RjKyGjpvpeeUFONCaQ  提取码:zgiw # coding:utf-8 import os impor ...

  3. Java序列化系列教程(下)

    一引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口 ...

  4. crosswalk 初步使用

    这里简单的说下 crossWalk 的配置; 我在学习 crosswalk 的时候,看到一篇博客,他所记录的已经是很完整的教程了: 点击查看 本文就根据该博客和官网说明,进行部分修改,补充; 首先 c ...

  5. HTML文档中class的命名规则以及命名规范

    1.采用英文字母.数字以及“-”和“_”命名. 2.以小写字母开头,不能以数字和“-”.“_”开头. 3.命名形式:单字,连字符,下划线和驼峰. 4.使用有意义命名. 其中(3).(4)条规定主要是便 ...

  6. SpringBoot整合SpringSecurity简单案例

    在我们开发项目的过程中经常会用到一些权限管理框架,Java领域里边经常用的可能就是shiro了,与之对应的还有SpringSecurity,SpringSecurity可以说是非常强大,与Spring ...

  7. FTP文件服务器

    import java.io.InputStream; import java.io.Serializable; import lombok.Data; @Data public class FtpB ...

  8. Android 性能优化(8)网络优化( 4)Optimizing App-Initiated Network Use

    Optimizing App-Initiated Network Use This lesson teaches you to Batch and Schedule Network Requests ...

  9. select多选

    1.css <style> .divBox{ width:400px; margin:100px auto; } .divBox span{ vertical-align:top; dis ...

  10. 371 Sum of Two Integers 两整数之和

    不使用运算符 + 和-,计算两整数a .b之和.示例:若 a = 1 ,b = 2,返回 3. 详见:https://leetcode.com/problems/sum-of-two-integers ...