1 条题解
-
0
自动搬运
来自洛谷,原作者为

FlashHu
**搬运于
2025-08-24 21:25:47,当前版本为作者最后更新于2018-01-24 21:11:12,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
关于LCT的其它问题可以参考一下我的博客
一道LCT很好的练习放懒标记技巧的题目。
一开始看到又做加法又做乘法的时候我是有点mengbi的。
然后我想起了模板线段树2。。。。。。(相信各位Dalao一定做过这道题)
这里的维护懒标记方法很像。除了翻转标记以外还要维护乘法标记和加法标记。
根据运算优先级,乘法是要先算的,所以先放,放的时候子树的,乘法标记,加法标记,儿子的统统都要乘一遍。
放加法标记的时候,想到线段树的区间大小是稳定的,而Splay并不是,所以还要维护,于是子树的要加上子树的再乘上标记,而儿子的和加法标记直接加上该标记的值。
再注意一个小细节。
~~有没有觉得51061这个数好小啊。。。~~我看到的时候特高兴,不用担心longlong的问题了。然而。。。
所以要开unsigned int。。。。。。
还是上代码吧
#include<cstdio> #include<cstdlib> #define R register unsigned int #define I inline #define YL 51061 #define lc c[x][0] #define rc c[x][1] #define mul(x) x*=c;x%=YL #define add(x,c) x+=c;x%=YL #define G ch=getchar() #define gc G;while(ch<'*')G #define in(z) gc;z=ch&15;G;while(ch>'*')z*=10,z+=ch&15,G; const int N=100009; unsigned int n,f[N],c[N][2],v[N],s[N],sz[N],lm[N],la[N],st[N]; bool r[N]; I bool nroot(R x){//好像Dalao都写的是isroot return c[f[x]][0]==x||c[f[x]][1]==x; } I void pushup(R x){ s[x]=(s[lc]+s[rc]+v[x])%YL; sz[x]=sz[lc]+sz[rc]+1; } I void pushr(R x){//翻转 R t=lc;lc=rc;rc=t;r[x]^=1; } I void pushm(R x,R c){//乘 mul(s[x]);mul(v[x]);mul(lm[x]);mul(la[x]); } I void pusha(R x,R c){//加 add(s[x],c*sz[x]);add(v[x],c);add(la[x],c); } I void pushdown(R x){ if(lm[x]!=1)pushm(lc,lm[x]),pushm(rc,lm[x]),lm[x]=1; if(la[x]) pusha(lc,la[x]),pusha(rc,la[x]),la[x]=0; if(r[x]) {if(lc)pushr(lc);if(rc)pushr(rc);r[x]=0;} } I void rotate(R x){ R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k]; if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;//注意if(nroot(y)),本蒟蒻经常忘写 if(w)f[w]=y;f[y]=x;f[x]=z; pushup(y); } I void splay(R x){ R y=x,z=0; st[++z]=y;//手动放个栈 while(nroot(y))st[++z]=y=f[y]; while(z)pushdown(st[z--]); while(nroot(x)){ y=f[x];z=f[y]; if(nroot(y)) rotate((c[y][0]==x)^(c[z][0]==y)?x:y); rotate(x); } pushup(x); } I void access(R x){ for(R y=0;x;x=f[y=x]) splay(x),rc=y,pushup(x); } I void makeroot(R x){ access(x); splay(x); pushr(x); } I void split(R x,R y){ makeroot(x); access(y); splay(y); } I void link(R x,R y){ makeroot(x);f[x]=y; } I void cut(R x,R y){ split(x,y);f[x]=c[y][0]=0; } int main() { register char ch; R q,i,a,b,k; in(n);in(q); for(i=1;i<=n;++i)v[i]=sz[i]=lm[i]=1;//注意乘法标记的初值为1 for(i=1;i<n;++i){ in(a);in(b); link(a,b); } while(q--){ gc; switch(ch){ case '+': in(a);in(b);in(k); split(a,b);pusha(b,k); break; case '-': in(a);in(b);cut(a,b); in(a);in(b);link(a,b); break; case '*': in(a);in(b);in(k); split(a,b);pushm(b,k); break; case '/': in(a);in(b); split(a,b); printf("%d\n",s[b]); } } return 0; }
- 1
信息
- ID
- 494
- 时间
- 2000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者