BZOJ4448 [Scoi2015]情报传递(洛谷P4216)

292 篇文章 1 订阅
281 篇文章 1 订阅

树链剖分

BZOJ题目传送门
洛谷题目传送门

把操作离线按时间排序,询问的时间减掉 c c <script type="math/tex" id="MathJax-Element-4">c</script>。修改的话就把节点打个1,第一个询问dep减一减,第二个询问树剖跳一跳就好了。当然主席树在线也是可以的。

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define F inline
using namespace std;
struct query{ int x,y,t,id,ans1,ans2; }q[N];
struct edge{ int nxt,to; }ed[N];
int n,m,k,s,ti,rt,h[N],t[N],sz[N],to[N],dep[N],id[N],tp[N],fa[N];
bool f[N];
F char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    return l==r?EOF:*l++;
}
F int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x;
}
F void writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
#define _write(x,y) writec(x),putchar(' '),writec(y),puts("")
F void mdfy(int x){ for (;x<=n;x+=x&-x) t[x]++; }
F int srch(int x){ for (s=0;x;x-=x&-x) s+=t[x]; return s; }
void dfs1(int x){
    dep[x]=dep[fa[x]]+1,sz[x]=1;
    for (int i=h[x],v;i;i=ed[i].nxt){
        dfs1(v=ed[i].to),sz[x]+=sz[v];
        if (sz[to[x]]<sz[v]) to[x]=v;
    }
}
void dfs2(int x){
    id[x]=++ti;
    if (to[x]) tp[to[x]]=tp[x],dfs2(to[x]);
    for (int i=h[x],v;i;i=ed[i].nxt)
        if ((v=ed[i].to)!=to[x]) tp[v]=v,dfs2(v);
}
F void find(int i){
    int ans=0,x=q[i].x,y=q[i].y;
    while (tp[x]!=tp[y]){
        if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
        ans+=srch(id[x])-srch(id[tp[x]]-1),x=fa[tp[x]];
    }
    if (dep[x]<dep[y]) swap(x,y);
    q[i].ans1=dep[q[i].x]+dep[q[i].y]-(dep[y]<<1)+1;
    q[i].ans2=ans+srch(id[x])-srch(id[y]-1);
}
#define add(x,y) ed[++k]=(edge){h[x],y},h[x]=k
F bool cmp1(query a,query b){ return a.t==b.t?a.y<b.y:a.t<b.t; }
F bool cmp2(query a,query b){ return a.id<b.id; }
int main(){
    n=_read();
    for (int i=1;i<=n;i++) fa[i]=_read(),fa[i]?add(fa[i],i):rt=i;
    dfs1(rt),tp[rt]=1,dfs2(rt),m=_read();
    for (int i=1;i<=m;i++)
        if ((q[i].id=i)&&(q[i].y=_read())==1)
            q[i].x=_read(),q[i].y=_read(),q[i].t=i-_read()-1;
        else q[i].x=_read(),q[i].y=-1,q[i].t=i;
    sort(q+1,q+m+1,cmp1);
    for (int i=1;i<=m;i++)
        if (~q[i].y) find(i);
        else if (!f[q[i].x]) mdfy(id[q[i].x]),f[q[i].x]=true;
    sort(q+1,q+m+1,cmp2);
    for (int i=1;i<=m;i++) if (~q[i].y) _write(q[i].ans1,q[i].ans2);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值