洛谷 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 < ...
随机推荐
- .NET 之 ORM 性能评测
.NET 之 ORM 性能评测 Why 你应该总能听到某ORM性能比Dapper高 你应该有如下疑问: 基准测试是否权威 基准测试的方式是否合理 基准测试的标准是否能够统一 统一基准测试标准/规范 如 ...
- 【转】实现LoadRunner多个场景的顺序执行
应用场景假设有3个不同的测试场景,分别为并发登录.核心业务.可靠性测试,3个场景有先后执行顺序.由于白天测试机器另有用处,只能在晚上进行性能测试,这时我们的期望是能否把测试场景都设定好之后晚上自动运行 ...
- Ioc 器管理的应用程序设计,前奏:容器属于哪里? 控制容器的反转和依赖注入模式
Ioc 器管理的应用程序设计,前奏:容器属于哪里? 我将讨论一些我认为应该应用于“容器管理”应用程序设计的原则. 模式1:服务字典 字典或关联数组是我们在软件工程中学到的第一个构造. 很容易看到使 ...
- eclipse maven 插件的安装和配置
maven3 安装: 安装 Maven 之前要求先确定你的 JDK 已经安装配置完毕.Maven是 Apache 下的一个项目.眼下最新版本号是 3.0.4.我用的也是这个. 首先去官网下载 Mave ...
- anaconda中新rdkit安装
1. 执行 conda create -c rdkit -n my-rdkit-env rdkit 该步骤经测试发现需FQ,而模拟器无法完成FQ(至少我不知道方法), 因此在本机上配置好环境后复制粘贴 ...
- Python爬虫开发【第1篇】【Scrapy shell】
Scrapy Shell Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据 ...
- 配置server禁止全部非法域名 訪问自己的server
1.Apache2.4.1曾经: 第一种 直接拒绝訪问 打开 httpd.conf 文件,将一下配置追加到文件最后. #直接拒绝全部非法域名 <VirtualHost *:80> Ser ...
- Android图片载入缓存框架Glide
Glide开源框架是Google推荐的图片载入和缓框架,其在Github上的开源地址是:https://github.com/bumptech/glide 当然一个Google推荐的框架肯定就是Vol ...
- B. Flag of Berland
B. Flag of Berland time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- YTU 2897: E--外星人供给站
2897: E--外星人供给站 时间限制: 2 Sec 内存限制: 128 MB 提交: 20 解决: 13 题目描述 外星人指的是地球以外的智慧生命.外星人长的是不是与地球上的人一样并不重要,但 ...