BZOJ4573 : [Zjoi2016]大森林
扫描线,从左到右依次处理每棵树。
用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1。
用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数。
添加或删除操作0就是单点换父亲,添加或删除操作1就是区间换父亲。可以通过添加虚点来实现区间换父亲操作。
时间复杂度$O(m\log m)$。
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int N=200010;
int n,m,i,j,op,x,y,z,cnt,L[N],R[N],q[N+5][2],ans[N],tot,ap[N];
int ga0[N],gd0[N],ga1[N],gd1[N],v[N<<1],nxt[N<<1],ed,G[N],V[N],W[N],NXT[N],cq;
set<int>T0,T1;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}
inline void addq(int x,int y,int z){V[++cq]=y;W[cq]=z;NXT[cq]=G[x];G[x]=cq;}
namespace DS{
const int M=N<<2;
int son[M][2],f[M],size[M];
struct P{
int x,y;
P(){x=y=0;}
P(int _x,int _y){x=_x,y=_y;}
inline P operator+(const P&v){return y>v.x?P(x,y-v.x+v.y):P(x+v.x-y,v.y);}
inline void operator+=(const P&v){*this=*this+v;}
}v[M],s[M];
inline void up(int x){
size[x]=size[son[x][0]]+size[son[x][1]]+1;
s[x]=s[son[x][0]]+v[x]+s[son[x][1]];
}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
}
inline void splay(int x,int w){
while(f[x]!=w){
int y=f[x];
if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(x);
}
void spilt(int x,int y){
splay(x,0);splay(y,x);
f[son[x][0]]=f[son[y][1]]=0;
if(son[x][0]&&son[y][1]){
int z=son[x][0];
while(son[z][1])z=son[z][1];
splay(z,0);
son[z][1]=son[y][1];
f[son[y][1]]=z;
up(z);
}
son[x][0]=son[y][1]=0;
up(y);up(x);
}
inline int rank(int x){
splay(x,0);
return size[son[x][0]];
}
inline int ask(int x,int y){
splay(x,0);splay(y,x);
P t=s[son[y][0]]+v[y];
return t.x+t.y;
}
inline void addright(int x,int y){
splay(x,0);
x=son[x][1];
while(son[x][0])x=son[x][0];
son[x][0]=y;
f[y]=x;
up(x);
splay(y,0);
}
inline void newnode(int o,int val,int z){
int x=o<<1,y=x|1;
v[x]=P(0,val),v[y]=P(val,0);
f[y]=x,son[x][1]=y;
up(y);up(x);
if(z)addright(z<<1,x);
}
}
inline void add0(int x){
int y=q[x][1];
set<int>::iterator j=T0.lower_bound(x);
j--;
DS::spilt(y<<1,y<<1|1);
if(q[*j][0])DS::addright(q[*j][1]<<1,y<<1);
else DS::addright(q[*j][1]<<1|1,y<<1);
T0.insert(x);
}
inline void del0(int x){
int y=q[x][1];
T0.erase(x);
DS::spilt(y<<1,y<<1|1);
}
inline void add1(int x){
int y=q[x][1];
set<int>::iterator j=T0.lower_bound(x),k;
if(*j<N&&!q[*j][0]){
k=T1.lower_bound(x);
k=T0.find(*k);
k--;
DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1);
DS::addright(y<<1,q[*j][1]<<1);
}
T0.insert(x);
T1.insert(x);
}
inline void del1(int x){
int y=q[x][1],pos;
T0.erase(x);
T1.erase(x);
set<int>::iterator j=T0.lower_bound(x),k,o;
if(*j<N&&!q[*j][0]){
k=T1.lower_bound(x);
k=T0.find(*k);
k--;
o=T0.lower_bound(x);
o--;
DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1);
if(q[*o][0])DS::addright(q[*o][1]<<1,q[*j][1]<<1);
else DS::addright(q[*o][1]<<1|1,q[*j][1]<<1);
}
}
inline int query(int x,int y){
if(x==y)return 0;
if(DS::rank(x<<1)>DS::rank(y<<1))swap(x,y);
return DS::ask(x<<1,y<<1);
}
int main(){
read(n),read(m);
L[cnt=1]=1,R[1]=n;
q[0][0]=q[0][1]=1;
for(i=1;i<=m+1;i++){
ap[i]=i;
DS::newnode(i,1,0);
}
tot=m+1;
for(i=1;i<=m;i++){
read(op),read(x),read(y);
if(!op){
L[++cnt]=x;R[cnt]=y;
q[i][1]=cnt;
add(ga0[x],i),add(gd0[y],i);
}
if(op==1){
read(z);
x=max(x,L[z]),y=min(y,R[z]);
if(x>y)continue;
DS::newnode(++tot,0,ap[z]);
ap[z]=tot;
q[i][0]=1,q[i][1]=tot;
add(ga1[x],i),add(gd1[y],i);
}
if(op==2)read(z),addq(x,y,z);
}
T0.insert(0),T0.insert(N);
T1.insert(0),T1.insert(N);
for(i=1;i<=n;i++){
for(j=ga0[i];j;j=nxt[j])add0(v[j]);
for(j=ga1[i];j;j=nxt[j])add1(v[j]);
for(j=G[i];j;j=NXT[j])ans[j]=query(V[j],W[j]);
for(j=gd0[i];j;j=nxt[j])del0(v[j]);
for(j=gd1[i];j;j=nxt[j])del1(v[j]);
}
for(i=1;i<=cq;i++)printf("%d\n",ans[i]);
return 0;
}
BZOJ4573 : [Zjoi2016]大森林的更多相关文章
- [BZOJ4573][ZJOI2016]大♂森林
bzoj luogu uoj sol \(orz\ \ HJT\ \ dalao\)教会我做这道题. 考虑每两个相邻位置的树的差异. 对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么 ...
- BZOJ4573:[ZJOI2016]大森林——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=4573 https://www.luogu.org/problemnew/show/P3348#sub ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- [ZJOI2016]大森林
Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...
- 【刷题】BZOJ 4573 [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力.小 ...
- bzoj 4573: [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树 都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. ...
- P3348 [ZJOI2016]大森林
\(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...
- 【LuoguP3348】[ZJOI2016]大森林
题目链接 题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y ...
- 【BZOJ4573】[ZJOI2016] 大森林(LCT)
点此看题面 大致题意: 有\(n\)棵树,初始各有\(1\)个编号为\(1\)的节点,且其为生长节点.\(3\)种操作:将\([l,r]\)区间内的树增加一个新的编号的节点,修改\([l,r]\)区间 ...
随机推荐
- Codeforces Round #327 (Div. 2)B(逻辑)
B. Rebranding time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- 通过mysql命令行理解mysql
引言:工具不可谓给我们的生活带来了便利,但有些时候我们却忘记了事物本身的意义.在大多数人都在追捧甚至是盲从各种各样的工具有多先进的时候,你是否有反思过:你目前是否有使用它的资格. 假设你学会了使用一款 ...
- Clr Via C#读书笔记---计算限制的异步操作
线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...
- JavaWeb学习之Path总结、ServletContext、ServletResponse、ServletRequest(3)
1.Path总结 1.java项目 1 File file = new File(""); file.getAbsolutePath(); * 使用java命令,输出路径是,当前j ...
- 【翻译十】java-固定锁和同步
Intrinsic Locks and Synchronization Synchronization is built around an internal entity known as the ...
- web magic 小结
缘起 写了多年的程序,鲜有产出物,于是最近打算做个不可说的东西来祭奠逝去的青春.数据,是一个程序的起点,我们没有数以亿计的用户,无法让活跃用户给我们产生数据,那就只能去别人的站点上借点数据了.这个功能 ...
- PAT A 1014. Waiting in Line (30)【队列模拟】
题目:https://www.patest.cn/contests/pat-a-practise/1014 思路: 直接模拟类的题. 线内的各个窗口各为一个队,线外的为一个,按时间模拟出队.入队. 注 ...
- Shadow SSDT详解、WinDbg查看Shadow SSDT
一.获取ShadowSSDT 好吧,我们已经在R3获取SSDT的原始地址及SDT.SST.KiServiceTbale的关系里面提到:所有的SST都保存在系统服务描述表(SDT)中.系统中一共有两个S ...
- Android之Inflate()
Inflate()作用就是将xml定义的一个布局找出来,但仅仅是找出来而且隐藏的,没有找到的同时并显示功能.最近做的一个项目就是这一点让我迷茫了好几天. Android上还有一个与Inflate( ...
- CSS 基本1
HTML元素可以分为两种: 块级元素 内联元素(行内元素) 两者的区别在于以下三点: 块级元素会独占一行(即无法与其他元素显示在同一行内,除非你显示修改元素的 display 属性),而内联元素则都会 ...