题解 洛谷P1501/BZOJ2631【[国家集训队]Tree II】
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】的更多相关文章
- 【洛谷 P1501】 [国家集训队]Tree II(LCT)
题目链接 Tree Ⅱ\(=\)[模板]LCT+[模板]线段树2.. 分别维护3个标记,乘的时候要把加法标记也乘上. 还有就是模数的平方刚好爆\(int\),所以开昂赛德\(int\)就可以了. 我把 ...
- 【洛谷1501】[国家集训队] Tree II(LCT维护懒惰标记)
点此看题面 大致题意: 有一棵初始边权全为\(1\)的树,四种操作:将两点间路径边权都加上一个数,删一条边.加一条新边,将两点间路径边权都加上一个数,询问两点间路径权值和. 序列版 这道题有一个序列版 ...
- 洛谷 P1501 [国家集训队]Tree II 解题报告
P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...
- P1501 [国家集训队]Tree II(LCT)
P1501 [国家集训队]Tree II 看着维护吧2333333 操作和维护区间加.乘线段树挺像的 进行修改操作时不要忘记吧每个点的点权$v[i]$也处理掉 还有就是$51061^2=2607225 ...
- BZOJ 2631 [国家集训队]Tree II (LCT)
题目大意:给你一棵树,让你维护一个数据结构,支持 边的断,连 树链上所有点点权加上某个值 树链上所有点点权乘上某个值 求树链所有点点权和 (辣鸡bzoj又是土豪题,洛谷P1501传送门) LCT裸题, ...
- 洛谷P1501 [国家集训队]Tree II(LCT,Splay)
洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
- 树链剖分【洛谷P1505】 [国家集训队]旅游
P1505 [国家集训队]旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城 ...
- 【洛谷】P4555 [国家集训队]最长双回文串
P4555 [国家集训队]最长双回文串 题源:https://www.luogu.com.cn/problem/P4555 原理:Manacher 还真比KMP好理解 解决最长回文串问题 转化为长度为 ...
随机推荐
- HDU 1724 Ellipse 【自适应Simpson积分】
Ellipse Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- Android编译详解之lunch命令 【转】
本文转载自: Android编译详解之lunch命令 (2012-10-08 10:27:55) 转载▼ 标签: it 分类: android内核剖析 Android的优势就在于其开源,手机和 ...
- 【USACO 2010FEB】 slowdown
[题目链接] 点击打开链接 [算法] dfs序 + 线段树 树链剖分同样可以解决这个问题 [代码] #include<bits/stdc++.h> using namespace std; ...
- mysql数据类型和java对应表(copy)
[说明] 资料来自:http://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-type-conversions.html My ...
- 栗染-git命令搭建简单的个人的网页
本来一个很简单的东西被自己搞了很久 可能是对于一个小白来说第一次认识到github的魅力吧,以前只是听别人说过用github搭建网站,听起来很厉害的样子,一直也没有尝试过,突然兴起今天去网上找一些教程 ...
- 用 python 写一个模拟玩家移动的示例
实例:二维矢量模拟玩家移动 在游戏中,一般使用二维矢量保存玩家的位置,使用矢量计算可以计算出玩家移动的位置,下面的 demo 中,首先实现二维矢量对象,接着构造玩家对象,最后使用矢量对象和玩家对象共同 ...
- DotnetCore(1)尝鲜构建Web应用
在上篇文章中DotnetCore环境安装完成后,现在我们来尝试构建Web应用. 新建文件夹NetCoreWebDemo,并cd进入NetCoreWebDemo文件夹 同时Ctrl+shift按下快捷键 ...
- laravel ORM 只开启created_at的方法
class User extends Model { //重写setUpdatedAt方法 public function setUpdatedAt($value) { // Do nothing. ...
- MVC、MVP和MVVM的图示
一.MVC MVC模式的意思是,软件可以分成三个部分. 视图(View):用户界面. 控制器(Controller):业务逻辑 模型(Model):数据保存 各部分之间的通信方式如下. View 传送 ...
- python2 'str' object has no attribute 'decode'
'.decode('hex') 上述代码,报错: 'str' object has no attribute 'decode' 查找原因: https://stackoverflow.com/ques ...