看来这个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的更多相关文章

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

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

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

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

  3. 【刷题】洛谷 P1501 [国家集训队]Tree II

    题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...

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

    题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...

  5. 洛谷P1501 [国家集训队]Tree II(打标记lct)

    题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...

  6. [洛谷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$, ...

  7. 洛谷 P1501 [国家集训队]Tree II Link-Cut-Tree

    Code: #include <cstdio> #include <algorithm> #include <cstring> #include <strin ...

  8. [洛谷P1501] [国家集训队]Tree II(LCT模板)

    传送门 这是一道LCT的板子题,说白了就是在LCT上支持线段树2的操作. 所以我只是来存一个板子,并不会讲什么(再说我也不会,只能误人子弟2333). 不过代码里的注释可以参考一下. Code #in ...

  9. 洛谷.1501.[国家集训队]Tree II(LCT)

    题目链接 日常zz被define里没取模坑 //标记下放同线段树 注意51061^2 > 2147483647,要开unsigned int //*sz[]别忘了.. #include < ...

随机推荐

  1. Linux驱动开发:USB驱动之usb_skel分析

    在学习了这么些天的驱动之后,个人觉得驱动就是个架构的问题,只要把架构弄清楚了 然后往里面添砖加瓦就可以了,所以似乎看起来不是太困难,但也许是是我经验不足吧,这只能算是个人浅见了 这两天在学习USB驱动 ...

  2. HashMap、HashTable、TreeMap 深入分析及源代码解析

    在Java的集合中Map接口的实现实例中用的比較多的就是HashMap.今天我们一起来学学HashMap,顺便学学和他有关联的HashTable.TreeMap 在写文章的时候各种问题搞得我有点迷糊尤 ...

  3. 项目中遇到的HQL查询问题

    问题描写叙述: 目的:想要查询出全部最新版本号的组件 说明:组件:版本号 =1:n关系 ,假设这个组件仅仅有一个版本号也要可以查出来. 项目中使用的是内存数据库,无法看到表结构,这里的样例仅仅用于模拟 ...

  4. leetCode 78.Subsets (子集) 解题思路和方法

    Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset must ...

  5. Dropbox电面面经

    他家电面有2轮,等待onsite.. . 电面1: 国人MM面的.这点感觉非常难得. 统计近期5分钟的点击量,实现hit和getHit两个函数.这题是他家高频题,我用deque实现的,hit的均摊时间 ...

  6. 鸟哥的Linux私房菜-----13、账号管理

  7. Redis 命令行 常用总结

    http://www.redis.cn/commands.html# 1 Keys * 列出所有的keys redis > keys * ) "s:0" ) "o: ...

  8. hdoj 5093 Battle ships 【二分图最大匹配】

    题目:pid=5093" target="_blank">hdoj 5093 Battle ships 题意:给你一个n*m的图,图中有冰山 '# ',浮冰 'o' ...

  9. 高效5步走,高速搭建Hadoop2伪分布环境

    前两天将Hadoop2的全然分布式搭建文档整理公布于网上(http://blog.csdn.net/aaronhadoop/article/details/24859369).朋友相邀.就再将Hado ...

  10. Cocos2d-X-3.0 之后的版本的环境搭建

     Cocos2d-X-3.0 之后的版本的环境搭建 由于cocos2d游戏开发引擎更新十分频繁,官方文档同步不够及时和完善.所以不要照着官方文档来照做生成工程. <点击图片就能进入网站> ...