洛谷 P1501 [国家集训队]Tree II
看来这个LCT板子并没有什么问题
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL md=;
namespace LCT
{
struct Node
{
Node *ch[],*fa;
bool rev;
LL addv,mulv;
LL dat,sum,sz;
void padd(LL x)
{
addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md;
}
void pmul(LL x)
{
addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md;
}
void upd()
{
sum=((ch[]?ch[]->sum:)+(ch[]?ch[]->sum:)+dat)%md;
sz=(ch[]?ch[]->sz:)+(ch[]?ch[]->sz:)+;
}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
}nodes[];
LL mem;
Node *getnode()
{
return nodes+(mem++);
}
bool isroot(Node *x)
{
return (!x->fa)||((x->fa->ch[]!=x)&&(x->fa->ch[]!=x));
}
bool gson(Node *o) {return o==o->fa->ch[];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
void rotate(Node *o,bool d)
//在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
{
Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
o->ch[!d]=k->ch[d];k->ch[d]=o;
o->upd();k->upd();
k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o;
}
Node *st[];LL top;
void solvetag(Node *o)
{
while(!isroot(o)) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
Node *fa,*fafa;bool d1,d2;
while(!isroot(o))
{
fa=o->fa;d1=(o==fa->ch[]);
if(isroot(fa)) rotate(fa,d1);
else
{
fafa=o->fa->fa;d2=(fa==fafa->ch[]);//要保证fa不是root之后才能获取这两个值,曾错过
if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
}
}
}
void access(Node *o)
{
for(Node *lst=NULL;o;lst=o,o=o->fa)
{
splay(o);//此处不pushdown是由于splay中保证进行过了
o->ch[]=lst;o->upd();//注意upd
}
}
Node *gtop(Node *o)
{
access(o);splay(o);
for(;o->ch[];o=o->ch[],o->pd());//此处不在开始前pushdown(o)是由于splay中保证进行过了
splay(o);return o;//听说这里不splay一下也很难卡掉
}
void mtop(Node *o) {access(o);splay(o);o->rev^=;}
void link(Node *x,Node *y)
{
if(gtop(x)==gtop(y)) return;
mtop(y);y->fa=x;
}
void cut(Node *x,Node *y)
{
mtop(x);access(y);splay(y);
if(y->ch[]!=x||x->ch[]) return;//如果x、y之间直接有边,那么上面一行的操作之后应当是x与y在单独一棵splay中,那么一定保证y左子节点是x且x没有右子节点
x->fa=y->ch[]=NULL;//注意,改的是x的父亲和y的子节点(虽然x的确是树的根,但是此时在splay上是y的子节点,不能搞混)
y->upd();//注意
}
LL query(Node *x,Node *y)
{
mtop(x);access(y);splay(y);
//if(gtop(y)!=x) return 0;//此题保证x与y连通,不需要
return y->sum;
}
void add(Node *x,Node *y,LL t)
{
mtop(x);access(y);splay(y);
y->padd(t);
}
void mul(Node *x,Node *y,LL t)
{
mtop(x);access(y);splay(y);
y->pmul(t);
}
}
LCT::Node *nd[];
LL n,q;char tmp[];
int main()
{
LL i,x,y,t,x2,y2;
scanf("%lld%lld",&n,&q);
for(i=;i<=n;i++)
{
nd[i]=LCT::getnode();
nd[i]->mulv=;nd[i]->dat=nd[i]->sum=;nd[i]->sz=;
}
for(i=;i<n;i++)
{
scanf("%lld%lld",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%lld%lld",&x,&y);
printf("%lld\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}
压行后:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL md=;
namespace LCT
{
struct Node
{
Node *ch[],*fa;
bool rev;
LL addv,mulv;
LL dat,sum,sz;
void padd(LL x)
{
addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md;
}
void pmul(LL x)
{
addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md;
}
void upd()
{
sum=((ch[]?ch[]->sum:)+(ch[]?ch[]->sum:)+dat)%md;
sz=(ch[]?ch[]->sz:)+(ch[]?ch[]->sz:)+;
}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
}nodes[];
LL mem;
Node *getnode()
{
return nodes+(mem++);
}
bool isroot(Node *x)
{
return (!x->fa)||((x->fa->ch[]!=x)&&(x->fa->ch[]!=x));
}
bool gson(Node *o) {return o==o->fa->ch[];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
void rotate(Node *o,bool d)
//在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
{
Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
o->ch[!d]=k->ch[d];k->ch[d]=o;
o->upd();k->upd();
k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o;
}
Node *st[];LL top;
void solvetag(Node *o)
{
while(!isroot(o)) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
Node *fa,*fafa;bool d1,d2;
while(!isroot(o))
{
fa=o->fa;d1=(o==fa->ch[]);
if(isroot(fa)) rotate(fa,d1);
else
{
fafa=o->fa->fa;d2=(fa==fafa->ch[]);//要保证fa不是root之后才能获取这两个值,曾错过
if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
}
}
}
void access(Node *o)
{
for(Node *lst=NULL;o;lst=o,o=o->fa)
{
splay(o);
o->ch[]=lst;o->upd();
}
}
Node *gtop(Node *o)
{
access(o);splay(o);
for(;o->ch[];o=o->ch[],o->pd());
splay(o);return o;
}
void mtop(Node *o) {access(o);splay(o);o->rev^=;}
void split(Node *x,Node *y) {mtop(x);access(y);splay(y);}
void link(Node *x,Node *y) {mtop(y);y->fa=x;}
void cut(Node *x,Node *y) {split(x,y);x->fa=y->ch[]=NULL;y->upd();}
LL query(Node *x,Node *y) {split(x,y);return y->sum;}
void add(Node *x,Node *y,LL t) {split(x,y);y->padd(t);}
void mul(Node *x,Node *y,LL t) {split(x,y);y->pmul(t);}
}
LCT::Node *nd[];
LL n,q;char tmp[];
int main()
{
LL i,x,y,t,x2,y2;
scanf("%lld%lld",&n,&q);
for(i=;i<=n;i++)
{
nd[i]=LCT::getnode();
nd[i]->mulv=;nd[i]->dat=nd[i]->sum=;nd[i]->sz=;
}
for(i=;i<n;i++)
{
scanf("%lld%lld",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%lld%lld",&x,&y);
printf("%lld\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}
重新打了一个板子
#include<cstdio>
#include<algorithm>
#include<cassert>
#define md 51061
using namespace std;
typedef long long LL;
int Add(int a,int b) {return (a+b)%md;}
int Add(int a,int b,int c) {return (a+b+c)%md;}
int Mul(int a,int b) {return LL(a)*b%md;}
namespace LCT
{
const int N=;
struct Node
{
Node *ch[],*fa;
bool rev;
int addv,mulv;
int dat,sum,sz;
void upd()
{
sum=Add((ch[]?ch[]->sum:),dat,(ch[]?ch[]->sum:));
sz=(ch[]?ch[]->sz:)++(ch[]?ch[]->sz:);
}
void padd(int x) {addv=Add(addv,x);dat=Add(dat,x);sum=Add(sum,Mul(x,sz));}
void pmul(int x) {addv=Mul(addv,x);mulv=Mul(mulv,x);dat=Mul(dat,x);sum=Mul(sum,x);}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
bool isroot() {return (!fa)||(this!=fa->ch[]&&this!=fa->ch[]);}
bool gson() {return this==fa->ch[];}
void rot()//将自身向上旋,要求已经完成下传标记
{
bool d=gson();Node *f=fa;
fa=f->fa;if(!f->isroot()) f->fa->ch[f->gson()]=this;
f->ch[d]=ch[!d];if(ch[!d]) ch[!d]->fa=f;
f->fa=this;ch[!d]=f;
f->upd();upd();
}
}nodes[N+];
Node *st[N+];int top;
int mem;
Node *getnode()
{
Node *t=nodes+mem++;t->mulv=;t->sz=;t->dat=t->sum=;
return t;
}
void solvetag(Node *o)
{
while(!o->isroot()) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
for(;!o->isroot();o->rot())
if(!o->fa->isroot())
o->gson()==o->fa->gson()?o->fa->rot():o->rot();
}
void acc(Node *o)
{
for(Node *lst=;o;lst=o,o=o->fa)
splay(o),o->ch[]=lst,o->upd();
}
void mtop(Node *o) {acc(o);splay(o);o->rev^=;}
void link(Node *x,Node *y) {mtop(y);y->fa=x;}
void cut(Node *x,Node *y) {mtop(x);acc(y);splay(y);x->fa=y->ch[]=;y->upd();}
int query(Node *x,Node *y) {mtop(x);acc(y);splay(y);return y->sum;}
void add(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->padd(t);}
void mul(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->pmul(t);}
}
LCT::Node *nd[];
int n,q;char tmp[];
int main()
{
int i,x,y,t,x2,y2;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++) nd[i]=LCT::getnode();
for(i=;i<n;i++)
{
scanf("%d%d",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%d%d%d",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%d%d%d%d",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%d%d%d",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%d%d",&x,&y);
printf("%d\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}
洛谷 P1501 [国家集训队]Tree II的更多相关文章
- 洛谷 P1501 [国家集训队]Tree II 解题报告
P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...
- 洛谷P1501 [国家集训队]Tree II(LCT,Splay)
洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...
- 【刷题】洛谷 P1501 [国家集训队]Tree II
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- 洛谷P1501 [国家集训队]Tree II(LCT)
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- 洛谷P1501 [国家集训队]Tree II(打标记lct)
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- [洛谷P1501][国家集训队]Tree II
题目大意:给一棵树,有四种操作: $+\;u\;v\;c:$将路径$u->v$区间加$c$ $-\;u_1\;v_1\;u_2\;v_2:$将边$u_1-v_1$切断,改成边$u_2-v_2$, ...
- 洛谷 P1501 [国家集训队]Tree II Link-Cut-Tree
Code: #include <cstdio> #include <algorithm> #include <cstring> #include <strin ...
- [洛谷P1501] [国家集训队]Tree II(LCT模板)
传送门 这是一道LCT的板子题,说白了就是在LCT上支持线段树2的操作. 所以我只是来存一个板子,并不会讲什么(再说我也不会,只能误人子弟2333). 不过代码里的注释可以参考一下. Code #in ...
- 洛谷.1501.[国家集训队]Tree II(LCT)
题目链接 日常zz被define里没取模坑 //标记下放同线段树 注意51061^2 > 2147483647,要开unsigned int //*sz[]别忘了.. #include < ...
随机推荐
- VS2012关于hash_map的使用简略
VS关于hash_map使用的一些经常使用构造方法汇总,包含基本类型和结构体,相信够一般模仿使用: # include<hash_map> #include<iostream> ...
- 聚合类新闻client产品功能点详情分析
产品功能点 功能 今日头条 百度新闻 鲜果 ZAKER 媒体订阅 × √ ★ ★ 个性化内容推荐 ★ √ × × 个性化订阅(RSS) × × ★ × 视频新闻 × × × × 评论盖楼 √ √ √ ...
- Web安全漏洞及攻击
背景介绍 先说一个在互联网上常见,但是普通人又不太理解的东西--“验证码”. 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell ...
- 【iOS9系列】-3DTouch开发
[iOS9系列]-3DTouch开发 第一:简介 3DTouch 是iOS9系统系统下,在iPhone6s(iPhone6s Plus)手机上才能够使用的功能.熟练使用后,发现还是很便捷的. 但是模拟 ...
- Win32 Windows编程 七
定时器消息 1. WM_TIMER 依照定时器设置的时间段,自己主动向窗体发送一个定时器消息WM_TIMER.优先级比較低 定时器精度比較低.毫秒级别.消息产生时间也精度比較低 2 .消息和函数 WM ...
- [IT学习]GIT 学习
最近开始了解GIT.有一些不错的资源记录在下面: 1.GIT for teams A book about teams cooperation. 2.GIT https://learngitbranc ...
- extends && implements
final声明的类不能被继承 方法的重写(@Override): 两同两小一大原则: 方法名相同,参数类型相同 子类返回类型小于等于父类方法返回类型(java里无论怎样都对) 子类抛出异常小于等于 ...
- YTU 2555: 老大的烦恼
2555: 老大的烦恼 时间限制: 1 Sec 内存限制: 128 MB 提交: 176 解决: 47 题目描述 万恶的小黑,布置了一道题给老大做:给你一个n位的数,现在要求 你随意删除m位后,任 ...
- YTU 2838: 改错题AB-装置连接
2838: 改错题AB-装置连接 时间限制: 1 Sec 内存限制: 128 MB 提交: 81 解决: 49 题目描述 注:本题只需要提交标记为修改部分之间的代码,请按照C++方式提交. 有AB ...
- HDU - 2586 How far away ?(离线Tarjan算法)
1.给定一棵树,每条边都有一定的权值,q次询问,每次询问某两点间的距离. 2.这样就可以用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就可以了. 这里的计算方法是,记下根结点到任意一 ...