【Bzoj4448】情报传递

24 篇文章 0 订阅
14 篇文章 0 订阅

题意

给一棵树和m个操作(持续m秒),操作如下
1.给一个点打上标记,被标记的点每秒加1危险度,(被标记时仍为0,后一秒为1)。
2.查询x,y的路径上有多少危险度大于k的点。


解析

这种每秒增加的标记显然是不好维护的。
考虑转化。
设某点在t时刻被标记,i时刻提出询问,那么此时它的危险度为i-t。
则有i-t>k,t

#include <cstdio>
#include <algorithm>

#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)

using std :: max;
using std :: min;

const int maxx = 200000 + 25;

typedef int Array[maxx];

int n,m,x,y,z,num,cnt,tot,f,rt,t;
int head[maxx],to[maxx<<1],nxt[maxx<<1];
int T[maxx];

Array son,ftr,dpt,top,rnk,size,ans,ans1;

class Que{

    public:
        int l,r,id;
        int v,pos,f;

}A[maxx];

bool cmp(Que a,Que b){
    return a.v == b.v? a.f < b.f : a.v < b.v;
}

bool cmp1(Que a,Que b){
    return a.id < b.id;
}

namespace Bit{

    void Add(int x,int k){
        for(int i=x;i<=n;i+=i&(-i))
            T[i] += k;
    }

    int Query(int l,int r){
        int ans = 0;
        for(int i=r;i;i-=i&(-i))
            ans += T[i];
        for(int i=l-1;i;i-=i&(-i))
            ans -= T[i];
        return ans;
    }

}

namespace Cute{

    using namespace Bit; 

    void Ins(int x,int y){
        if((!x) || (!y)) return;
        to[++num] = y;nxt[num] = head[x];head[x] = num;
    }

    void Dfs1(int x){
        size[x] = 1;
        for(int i=head[x];i;i=nxt[i]){
            if(to[i] == ftr[x]) continue;
            dpt[to[i]] = dpt[x] + 1;ftr[to[i]] = x;
            Dfs1(to[i]);size[x] += size[to[i]];
            if(size[to[i]] > size[son[x]]) son[x] = to[i];
        }
    }

    void Dfs2(int x,int brn){
        rnk[x] = ++cnt;top[x] = brn;
        if(son[x]) Dfs2(son[x],brn);
        for(int i=head[x];i;i=nxt[i])
            if(to[i] != ftr[x] && to[i] != son[x])
                Dfs2(to[i],to[i]);
    }

    int Get(int x,int y,int &t){
        int ans = 0;t = dpt[x] + dpt[y];
        while(top[x] != top[y]){
            if(dpt[top[x]] > dpt[top[y]]) std :: swap(x,y);
            ans += Query(rnk[top[y]],rnk[y]);
            y = ftr[top[y]];
        }
        if(rnk[x] > rnk[y]) std :: swap(x,y);
        ans += Query(rnk[x],rnk[y]);
        t -= 2*dpt[x];t ++;
        return ans;
    }

}

using namespace Cute;

int main(){
    scanf("%d",&n);
    Rep( i , 1 , n ){
        scanf("%d",&x);
        if(x == 0) rt = i;
        Ins(i,x),Ins(x,i);
    }
    Dfs1(rt),Dfs2(rt,rt);
    scanf("%d",&m);
    Rep( i , 1 , m ){
        scanf("%d",&f);
        if(f == 2) scanf("%d",&x),A[i].pos = x,A[i].v = i;
        if(f == 1){
            scanf("%d%d%d",&x,&y,&z);
            A[i].l = x;A[i].r = y;
            A[i].v = i-z-1;
            A[i].f = 1;A[i].id = i;
        }
    }
    std :: sort(A+1,A+m+1,cmp);
    Rep( i , 1 , m ){
        if(A[i].f == 0) Add(rnk[A[i].pos],1);
        if(A[i].f == 1){
            Get(A[i].l,A[i].r,t);
            ans[A[i].id] = t;
            ans1[A[i].id] = Get(A[i].l,A[i].r,t);
            //printf("%d %d\n",t,Get(A[i].l,A[i].r,t));
        }
    }
    std :: sort(A+1,A+m+1,cmp1);
    Rep( i , 1 , m ) if(A[i].f) printf("%d %d\n",ans[A[i].id],ans1[A[i].id]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值