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;
}

  

时间: 2024-11-09 06:59:17

BZOJ4573 : [Zjoi2016]大森林的相关文章

P3348 [ZJOI2016]大森林(LCT)

Luogu3348 BZOJ4573 DarkBZOJ4573 题解 对于每个1操作建一个虚点,以后的0操作都连在最近建好的虚点上.这样每次整体嫁接的时候,直接把这个虚点断掉它原来的父亲,再link过去就可以了 求在x位置的两点之间距离,只要之前的换点加点操作完成,就可以计算,而且也要马上计算,之后树的形态就又要变了,这样保证了复杂度 #include<cstdio> #include<cstring> #include<algorithm> #include<i

●洛谷P3348 [ZJOI2016]大森林

题链: https://www.luogu.org/problemnew/show/P3348 题解: LCT,神题 首先有这么一个结论: 每次的1操作(改变生长点操作),一定只会会对连续的一段区间产生影响. (即不存在对两段不相连的区间都进行了该操作的情况,令这种情况为[2]) 简单来说就是因为该操作需要对应的那些树存在那个节点. 如果发生了情况[2],即表明区间[l1,r1],[l2,r2]有节点x,且[l1+1,r2-1]无节点x,且r2-1>=l1+1 但是我们的生长操作0操作每次进行的

洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不同树的影响. 假设有一个2操作形如\(l\ r\ x\),那么从微观来看差异,我们只关注第l-1棵树和第l棵树.再假设以后都没有了1操作,那么我们可以认为,第l棵树是第l-1棵树把这个1操作以后嫁接在原来生长节点上的所有节点(以及所有子树)全部转而嫁接到x上.再看第r棵树和第r+1棵树,是不是可以认

模式识别(Pattern Recognition)学习笔记(三十)--随机森林(Random Forest)

引言 模式识别是一门基于数据的学科,因此所有的模式识别问题都会面临的同一个问题就是数据的随机性问题.模式识别中每个方法的实现都是基于一个特定的数据样本集的,但是这个样本集只是所有可能的样本中的一次随机抽样,毕竟在我们的生活实际中存在着万物众生,多到我们数也数不清,甚至计算机都无法统计的清,而我们搜集到的充其量只是其中很小很小的一部分,这也是为什么机器学习中缺少的只是数据,只要有足够多的学习数据,就一定能取得惊人的结果,因此模式识别和机器学习中的很多方法的实现结果都无疑会受到这种随机性的影响,我们

一些$LCT$的瓜皮题目

一些瓜皮 放几个比较优(she)秀(pi)的\(LCT\)题. 老惯例,每一题代码因为一些未知原因消失了(如果要的话私我好了,虽然会咕咕咕). 嘴巴\(AC\)真香! [SP16580] QTREE7 对黑色.白色各开一棵有根\(LCT\). 若\(x\)点加入颜色\(c\)集合,则在\(c\)的那颗\(LCT\)上连接\((x,fa_x)\),在另一棵上断掉父亲边. 查询时,首先判断根结点是否在当前颜色集合内. 如果在的话直接查整棵\(LCT\). 否则走向右儿子,查询对应子树. 什么子树最大

垡章敲哿彰bk6f5g4rcseksop4l90

第六十一章 永冻之域与黄金之芒(中)贝贝和唐雅确实有很多事要忙,唐雅之所以急于获得第三魂环就是为了能够顺利通过四年级的升学考核.升学之后也有更多的事情等着他们.霍雨浩曾独自前往星斗大森林并且获得了魂环,自己照顾自己的能力很强,他们也不用担心什么.从他双手之中,至少飞射出数十片黄金叶.瞬间在空中形成一片黄金之网,悍然迎击向了贝贝的雷霆万钧.而此时,朱露.巫风和邪幻月三人才刚刚从三生镇魂鼎的阻挡下冲出来.王言也有些不知道该如何回答霍雨浩这个问题.叹息一声,道:"这次任务的挫折,责任在我,是我没有指挥

游蕴捞究似k60t0hau368

血狼狂吼一声,双脚发力,风驰电掣般向前冲出,在冲锋的同时,他的身体开始剧烈变化.银灰色的毛发疯长,全身肌肉.骨骼都在以惊人的速度变大,变化最大的是头部,嘴突出,獠牙外露.双腿变得格外粗壮,双手则化为利爪.身上的第一魂环已经在光芒闪烁.强大的震荡力一下就将江楠楠的身体向外代开,同时也将对手两人笼罩其中,杨一凡的匕首落空了,但宇梦迪的圣曜十字斩却迸发出强烈金光,眼看就要突破重围而出.十二名尸奴向受到霍雨浩灵魂冲击后暂时晕眩的死神使者发动了疯狂的攻击.那完全是不顾自身安危自杀式的战斗方式.怒火在心中熊

脱挚诼鞠旧w4hw605id97f8g6672ht

"哈哈哈哈--"众位宿老顿时集体笑场了.四位院长也是忍俊不禁,仙琳儿甚至用手捂住了自己的脸.刺耳的摩擦中,尽管那已经化为坚硬金属的双翼挡住了戴钥衡的去路,但是,戴钥衡锋锐的金色虎爪却在摩擦中硬生生的抓入了对手的双翼之中."就两个?"周漪眉毛挑了挑,"真是一群废物.难道你们不知道什么叫不敢惹事是庸才吗?除了他们俩以外,其他人全都给我出去,绕着史莱克广场跑一百圈.谁跑不完,直接开除."天梦冰蚕道:"倒不是只有我那里才有精神属性的魂兽.星斗大

涌掩涯用抡in962w3d7m00e2420j9o

梦红尘虽然失去了魂导器辅助飞行的能力,但她的修为毕竟远在霍雨浩和王冬之上,细剑展开的时候,就已是腾身而起.之前的杜维伦作出这样的决定,无疑是要看看霍雨浩的能力究竟是什么.否则的话,以霍雨浩那天的表现,只是凭一个模拟魂技就足以让他通过考核了啊!完美模拟.伴随着精神力的提升,霍雨浩对灵眸的技能运用的更加娴熟,闭关之后,他彻底领悟了自身魂技伴随年限提升后的威能,模拟魂技的模拟范围也从原本的直径三米变成了五米--当他看到远处东方那一抹紫意的时候,仿佛有浓浓的暖意顺着自己的灵眸流淌入脑海之中,眼眸得到了前