洛谷 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 < ...
随机推荐
- Angular2.x-显示heroes列表
在此页面中,您将展开Tour of Heroes应用程序以显示heroes列表,并允许用户选择heroes并显示heroes的详细信息. 6.X 你需要一些heroes来展示. 最终你会从远程数据服务 ...
- protobuf 一个c++示例
http://wangjunle23.blog.163.com/blog/static/11783817120126155282640/ 1.在.proto文件中定义消息格式 2.使用prot ...
- protobuf 之 MessageLite 接口摘录
class LIBPROTOBUF_EXPORT MessageLite { public: inline MessageLite() {} virtual ~MessageLite(); // Ba ...
- POJ 1061 青蛙的约会(扩展GCD求模线性方程)
题目地址:POJ 1061 扩展GCD好难懂.. 看了半天.最终把证明什么的都看明确了. .推荐一篇博客吧(戳这里),讲的真心不错.. 直接上代码: #include <iostream> ...
- 1 TypeScript 简介与安装
简介: TypeScript 是一种由微软开发维护的自由和开源的编程语言,它是JavaScript的一个超集,支持可选的类型检查,扩展了JavaScript的语法,支持JavaScript的所有语法和 ...
- Navicat for MySQL出现1030-Got error 28 from storage engine错误
Navicat for MySQL出现1030-Got error 28 from storage engine错误 刚刚还能用这会儿就用不了了,估计是磁盘空间不足引起的! 在根目录/下执行命令:d ...
- 2016/3/27 PHP中include和require的区别详解
1.概要 require()语句的性能与include()相类似,都是包括并运行指定文件.不同之处在于:对include()语句来说,在执行文件时每次都要进行读取和评估:而对于require()来说, ...
- Tomcat最多支持并发多少用户?
当一个进程有 500 个线程在跑的话,那性能已经是很低很低了.Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大.当某个应用拥有 250 个以上并发 ...
- MkDocs -- Project documentation with Markdown
/************************************************************************ * MkDocs -- Project docume ...
- 《JAVA与模式》之调停者模式
调停者模式是对象的行为模式.调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显引用.从而使它们可以较松散地耦合.当这些对象中的某些对象之间的相互作用发生改变时,不会立即影响到其他的一些 ...