[BZOJ2631]tree(LCT)
2016-03-28 17:00
323 查看
题目描述
传送门题解
板子题= =要注意的是这里×和+的操作用到了一点小技巧。你可能也发现了先加后乘和先乘后加是不一样的。
刚开始觉得在标记的时候先下方以前的标记,那可是如果下面还有标记怎么办呢?那可没边了= =
看了题解才知道,有一种非常巧妙的方式来保证每一次先乘后加是正确的。具体的看代码。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define LL unsigned int const int max_n=1e5+5; const int Mod=51061; int n,q,x,y,u,v,c,u1,v1,u2,v2; int f[max_n],ch[max_n][2],size[max_n],reverse[max_n]; LL key[max_n],sum[max_n],add[max_n],mul[max_n]; int strack[max_n]; inline int get(int x){ return ch[ f[x] ][1]==x; } inline int Is_Root(int x){ return ch[ f[x] ][0]!=x&&ch[ f[x] ][1]!=x; } inline void update(int x){ if (x){ sum[x]=key[x]; if (ch[x][0]) sum[x]=(int)((LL)(sum[x]+sum[ ch[x][0] ])%Mod); if (ch[x][1]) sum[x]=(int)((LL)(sum[x]+sum[ ch[x][1] ])%Mod); size[x]=1; if (ch[x][0]) size[x]+=size[ ch[x][0] ]; if (ch[x][1]) size[x]+=size[ ch[x][1] ]; } } inline void mark(int x,LL y,LL z){ key[x]=(key[x]*z+y)%Mod; sum[x]=(sum[x]*z+size[x]*y)%Mod; add[x]=(add[x]*z+y)%Mod; mul[x]=(mul[x]*z)%Mod; } inline void pushdown(int x){ if (x){ if (reverse[x]){ swap(ch[x][0],ch[x][1]); if (ch[x][0]) reverse[ ch[x][0] ]^=1; if (ch[x][1]) reverse[ ch[x][1] ]^=1; reverse[x]=0; } if (add[x]!=0||mul[x]!=1){ if (ch[x][0]) mark(ch[x][0],add[x],mul[x]); if (ch[x][1]) mark(ch[x][1],add[x],mul[x]); add[x]=0; mul[x]=1; } } } inline void rotate(int x){ int old=f[x],oldf=f[old],which=get(x); if (!Is_Root(old)) ch[oldf][ ch[oldf][1]==old ]=x; f[x]=oldf; ch[old][which]=ch[x][which^1]; f[ ch[old][which] ]=old; ch[x][which^1]=old; f[old]=x; update(old); update(x); } inline void splay(int x){ int temp=0; strack[++temp]=x; for (int i=x; !Is_Root(i); i=f[i]) strack[++temp]=f[i]; for (int i=temp;i>=1;--i) pushdown(strack[i]); for (int fa; !Is_Root(x); rotate(x)) if (!Is_Root(fa=f[x])) rotate( (get(x)==get(fa)) ?fa:x ); } inline void Access(int x){ int t=0; for (; x; t=x,x=f[x]){ splay(x); ch[x][1]=t; update(x);// } } inline void Reverse(int x){ Access(x); splay(x); reverse[x]^=1; } inline void Link(int x,int y){ Reverse(x); f[x]=y; splay(x); } inline void Cut(int x,int y){ Reverse(x); Access(y); splay(y); ch[y][0]=f[x]=0; } inline void Add(int x,int y,int z){ Reverse(x); Access(y); splay(y); mark(y,z,1); } inline void Mul(int x,int y,int z){ Reverse(x); Access(y); splay(y); mark(y,0,z); } inline int Query(int x,int y){ Reverse(x); Access(y); splay(y); return sum[y]; } int main(){ // freopen("input.txt","r",stdin); scanf("%d%d",&n,&q); for (int i=1;i<=n;++i) key[i]=mul[i]=1; for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); Link(x,y); } for (int i=1;i<=q;++i){ char cc=getchar(); while (cc!='+'&&cc!='-'&&cc!='*'&&cc!='/') cc=getchar(); if (cc=='+'){ scanf("%d%d%d",&u,&v,&c); Add(u,v,c); } if (cc=='-'){ scanf("%d%d%d%d",&u1,&v1,&u2,&v2); Cut(u1,v1); Link(u2,v2); } if (cc=='*'){ scanf("%d%d%d",&u,&v,&c); Mul(u,v,c); } if (cc=='/'){ scanf("%d%d",&u,&v); int ans=Query(u,v); printf("%d\n",ans); } } }
总结
板子要打熟,抵制手残然而光把板子打熟也没什么用= =向这种特殊的处理方式自己能不能想出来呢?
相关文章推荐
- 【C++】JSON数据解析——jsoncpp的使用
- HTML学习笔记(一)
- 类中const放在成员函数的前后有什么区别?
- mysql配置的讲解 mysql的root密码重置 mysql的登录
- 网络基础---IP地址
- Maven安装过程及手动添加JAR包到本地仓库详解
- PHP面试题目搜集
- Swift2.0下UICollectionViews拖拽效果的实现
- JVM内存管理
- Ubuntu 14.04 下搭建SVN服务器 svn://
- Autofac创建实例的方法总结
- clr相关的一些工具
- Spring第十篇—举例实现AOP
- Spring第十一篇——–Spring整合Hibernate之配置数据源
- XSS跨站脚本攻击过程最简单演示
- SpringMVC集成Bean Validation 1.1
- 工作流
- android WebView控件使用事项
- 理解 __declspec(dllexport)和__declspec(dllimport)
- C++客户端对mongodb的调用语法