「ZJOI2016」大森林

题目描述

小 Y 家里有一个大森林,里面有 n n n 棵树,编号从 1 1 1 n n n。一开始这些树都只是树苗,只有一个节点,标号为 1 1 1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小 Y 掌握了一种魔法,能让第 l l l 棵树到第 r r r 棵树的生长节点长出一个子节点。同时她还能修改第 l l l 棵树到第 r r r 棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?
第一行包含两个正整数 n , m n,m n,m,表示共有 n n n 棵树和 m m m 个操作。

接下来 m m m 行,每行包含若干非负整数表示一个操作,操作格式为:

0 l r 表示将第 l l l 棵树到第 r r r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 0 0 号操作叶子标号加 1 1 1(例如,第一个 0 0 0 号操作产生的子节点标号为 2 2 2), l l l r r r 之间的树长出的节点标号都相同。保证 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1lrn

1 l r x 表示将第 l l l 棵树到第 r r r 棵树的生长节点改到标号为 x x x 的节点。对于 i i i ( l ≤ i ≤ r ) (l \leq i \leq r) (lir) 这棵树,如果标号 x x x 的点不在其中,那么这个操作对该树不产生影响。保证 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1lrn x x x 不超过当前所有树中节点最大的标号。

2 x u v 询问第 x x x 棵树中节点 u u u 到节点 v v v 点的距离,也就是在第 x x x 棵树中从节点 u u u 和节点 v v v 的最短路上边的数量。保证 1 ≤ x ≤ n 1 \leq x \leq n 1xn,这棵树中节点 u u u 和节点 v v v 存在。
输出包括若干行,按顺序对于每个小 Y 的询问输出答案

样例输入

5 5
0 1 5
1 2 4 2
0 1 4
2 1 1 3
2 2 1 3

样例输出

1
2

数据范围

N ≤ 1 0 5 ,   M ≤ 2 × 1 0 5 N \leq 10^5, \ M \leq 2 \times 10^5 N105, M2×105

体节

0号操作只会对1号操作的范围造成影响,除此之外可以看作所有树都加了某一个点。
先假设所有操作都是针对所有树的。对每一个1号操作建立新的虚点,虚点连向操作改的那个点。生长的时候新的叶子连向上一次的虚点。
在操作只针对部分树的时候,先把所有虚点连向上一个虚点。将修改拆成左端点和右端点加一。将修改和询问按照树的编号排序。当进行到左端点的时候,将虚点的父亲连向实点;右端点把虚点的父亲连向上一个虚点。
讲的不清楚,直接看代码吧。。。
另:请注意,最后答案为:路径实点的数量-[LCA是虚点],可能要注意一下。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;
const int Q=433333;
int si[Q],fa[Q],ls[Q],rs[Q],ct[Q];
void upd(int x)
{
    si[x]=si[ls[x]]+si[rs[x]]+ct[x];
}
bool isroot(int x)
{return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void xxx(int x)
{
    int y=fa[x],z=fa[y];
    if(ls[z]==y)ls[z]=x;
    if(rs[z]==y)rs[z]=x;
    if(ls[y]==x)ls[y]=rs[x],fa[ls[y]]=y,rs[x]=y;
    else rs[y]=ls[x],fa[rs[y]]=y,ls[x]=y;
    fa[x]=z,fa[y]=x;
    upd(y),upd(x);
}
void splay(int x)
{
    while(!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if(!isroot(y))
            if((ls[z]==y&&ls[y]==x)||(rs[z]==y&&rs[y]==x))
                xxx(y),xxx(x);
            else xxx(x),xxx(x);
        else xxx(x);
    }
}
int AC(int x)
{
    int t=0;
    while(x)
    {
        splay(x);
        rs[x]=t;
        upd(x);
        t=x;
        x=fa[x];
    }
    return t;
}
void link(int x,int y)
{
    splay(x);
    fa[x]=y;
}
void cut(int x)
{
    AC(x);
    splay(x);
    fa[ls[x]]=0;
    ls[x]=0;
    upd(x);
}
int maxq=0;
struct qu{
    int tr,p,x,y;
}q[Q];
bool operator<(qu a,qu b)
{
    return a.tr==b.tr?a.p<b.p:a.tr<b.tr;
}
int ans[Q],pt[Q];
int tre[Q];
int AL[Q],AR[Q];
int main()
{
    int n,m,tot=2,lasroot=2;
    int x,y,id,apr=1,v;
    scanf("%d%d",&n,&m);
    int OB=0;
    tre[1]=1;
    si[1]=ct[1]=1;
    AL[1]=-1,AR[1]=998244353;
    si[2]=ct[2]=0;
    link(2,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&id);
        if(!id)
        {
            scanf("%d%d",&x,&y);
            ct[++tot]=1;
            si[tot]=1;
            link(tot,lasroot);
            tre[++apr]=tot;
            AL[apr]=x,AR[apr]=y;
        }
        else if(id==1){
            scanf("%d%d%d",&x,&y,&v);
            x=max(x,AL[v]),y=min(y,AR[v]);
            if(x>y)continue;
            ct[++tot]=0;
            si[tot]=0;
            link(tot,lasroot);
            q[++maxq]=(qu){x,i-m,tot,tre[v]};
            q[++maxq]=(qu){y+1,i-m,tot,lasroot};
            lasroot=tot;
        }
        else{
            scanf("%d%d%d",&v,&x,&y);
            q[++maxq]=(qu){v,i,tre[x],tre[y]},pt[i]=++OB;
        }
    }
    sort(q+1,q+maxq+1);
    for(int i=1;i<=maxq;i++)
    {
        x=q[i].x,y=q[i].y;
        if(q[i].p>0)
        {
            id=pt[q[i].p];
            AC(x);splay(x);
            ans[id]+=si[x];
            int t=AC(y);splay(y);
            ans[id]+=si[y];
            AC(t),splay(t);
            ans[id]-=(si[t]<<1);
        }
        else{
            cut(x);
            link(x,y);
        }
    }
    for(int i=1;i<=OB;i++)
        printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
zjoi2019是指第八届浙江省信息学奥林匹克竞赛(Zhejiang Olympiad in Informatics, zjoi),是浙江省级的信息学竞赛活动。这项竞赛旨在发掘和培养浙江省优秀的信息学人才,提高学生在计算机科学和算法设计等方面的能力。zjoi2019分为两个阶段,分别是省赛和决赛。 省赛是选拔赛阶段,所有报名参赛的学生都可以参加。在省赛中,学生将进行一系列的算法编程测试,测试他们在解决实际问题过程中的编程能力、算法设计思维和团队合作能力。省赛中表现优秀的选手将有机会晋级到决赛。 决赛是省选的最终阶段,在决赛中,选手将经历更加复杂和挑战性的编程测试。他们将面对更高难度的算法问题和实际应用问题,需要发挥出自己的创造力和思维能力,迅速解决问题。决赛中表现出色的选手将有机会代表浙江省参加全国性的信息学奥林匹克竞赛。 通过参加zjoi2019浙江省选,学生们将接触到高水平的算法竞赛,提升自己的编程和算法设计能力。同时,他们还能与其他对信息学感兴趣的同学们进行交流和学习,拓宽自己的视野,培养团队合作和竞赛意识。此外,脱颖而出的选手还有机会获得奖项和奖学金等荣誉,为自己的学术和职业道路打下坚实的基础。 总之,zjoi2019浙江省选是对浙江省信息学人才的全面选拔和培养,为学生们提供了一个展示自己技能和才华的舞台。这对于提高学生们的算法设计和编程能力、培养他们的团队合作精神和创新能力具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值