洛谷 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 < ...
随机推荐
- DataGridView依据下拉列表显示数据
我们都知道,DataGridView能够直接绑定数据源.显示数据库中的数据.可是我想做的是能够对他进行条件查询,依据用户级别选择不同级别的记录. 以上这个控件就是DataGridView控件,能够用它 ...
- Angular团队公布路线图,并演示怎样与React Native集成
本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2015/06/angular-2-react-native-roadmap 前不久在旧 ...
- 获取Windows用户所有的账户名
/// <summary> /// 设置用户密码 /// </summary> [DllImport("Netapi32.dll")] extern sta ...
- APache POI emaple ()
Business Plan The BusinessPlan application creates a sample business plan with three phases, weekly ...
- Use Local Or Global Index?
常常我们须要将大表依据分区键进行分区,当建立索引的时候.我们究竟使用local 还是global 索引呢 先看看两种索引的特点: 本地索引特点: 1. 本地索引一定是分区索引.分区键等同于表的分区键. ...
- 深度学习主机环境配置: Ubuntu16.04+Nvidia GTX 1080+CUDA8.0
不多说,直接上干货! 深度学习主机环境配置: Ubuntu16.04+Nvidia GTX 1080+CUDA8.0
- GCC 编译详解 (转)
GNU CC(简称为Gcc)是GNU项目中符合ANSI C标准的编译系统,能够编译用C.C++和Object C等语言编写的程序.Gcc不仅功能强大,而且可以编译如C.C++.Object C.Jav ...
- Bash Shell 解析路径获取文件名称和文件夹名
前言 还是今天再写一个自己主动化打包脚本.用到了从路径名中获取最后的文件名称.这里记录一下实现过程. 当然,最后我也会给出官方的做法.(ps:非常囧,实现完了才发现原来Bash Shell有现成的函数 ...
- (13)javaWeb中HttpServletRequest详解
关于HTTP请求和响应,可以参考 HTTP协议 系列文章 导学,请求概述: a,GET和POST请求报文格式: b,常见的请求头 在servlet中,相应的doGet方法和doSet方法中的reque ...
- Powershell 常见问题
unapproved verbs WARNING: The names of some imported commands from the module 'todo' include unappro ...