BZOJ4448 SCOI2015情报传递(离线+树链剖分+树状数组)

  即滋磁单点修改,询问路径上小于某数的值有多少个。暴力树剖套个主席树(或者直接树上主席树,似乎就1个log了?感觉不一定比两个log快)即可,然而不太优美。

  开始觉得可以cdq,然而就变成log^3了。冷静一下感觉简直是个弱智,修改本身就是单调的,只要对询问离线即可。树剖+BIT即可维护。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 200010
int n,m,root,fa[N],deep[N],p[N],t=0,cnt,cntu,cntq;
int top[N],id[N],son[N],size[N],tree[N];
struct data{int to,nxt;
}edge[N];
struct data2{int x,i;
}u[N];
struct data3{int x,y,z,i,ans;
}q[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
bool cmp(const data3&a,const data3&b)
{
    return a.z<b.z;
}
bool cmp1(const data3&a,const data3&b)
{
    return a.i<b.i;
}
void dfs1(int k)
{
    size[k]=1;
    for (int i=p[k];i;i=edge[i].nxt)
    {
        deep[edge[i].to]=deep[k]+1;
        dfs1(edge[i].to);
        size[k]+=size[edge[i].to];
        if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to;
    }
}
void dfs2(int k,int from)
{
    top[k]=from;id[k]=++cnt;
    if (son[k]) dfs2(son[k],from);
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=son[k]) dfs2(edge[i].to,edge[i].to);
}
void mbit(int k){while (k<=n) tree[k]++,k+=k&-k;}
int qbit(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
int lca(int x,int y) 
{
    while (top[x]!=top[y])
    {
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    return deep[x]<deep[y]?x:y;
}
int query(int x,int y)
{
    int s=0;
    while (top[x]!=top[y])
    {
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
        s+=qbit(id[x])-qbit(id[top[x]]-1);
        x=fa[top[x]];
    }
    if (deep[x]<deep[y]) swap(x,y);
    s+=qbit(id[x])-qbit(id[y]-1);
    return s;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4448.in","r",stdin);
    freopen("bzoj4448.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++)
    {
        fa[i]=read();
        if (fa[i]==0) root=i,fa[i]=i;
        else addedge(fa[i],i);
    }
    dfs1(root);
    dfs2(root,root);
    m=read();
    for (int i=1;i<=m;i++)
    {
        int op=read();
        if (op==1) cntq++,q[cntq].x=read(),q[cntq].y=read(),q[cntq].z=i-read()-1,q[cntq].i=i;
        else cntu++,u[cntu].x=read(),u[cntu].i=i;
    }
    sort(q+1,q+cntq+1,cmp);
    int x=0;
    for (int i=1;i<=cntq;i++)
    if (q[i].z>0)
    {
        while (x<cntu&&u[x+1].i<=q[i].z) mbit(id[u[++x].x]);
        q[i].ans=query(q[i].x,q[i].y);
    }
    sort(q+1,q+cntq+1,cmp1);
    for (int i=1;i<=cntq;i++)
    printf("%d %d\n",deep[q[i].x]+deep[q[i].y]-(deep[lca(q[i].x,q[i].y)]<<1)+1,q[i].ans);
    return 0;
}

 

posted @ 2018-10-30 14:42  Gloid  阅读(185)  评论(0编辑  收藏  举报