NOIP 模拟 $14\; \text{影魔}$

题解 \(by\;\;zj\varphi\)

不是原题

一道(对我来说)很需要技巧的题

对于颜色数如何处理

  1. 离线,将子树转化为 \(dfs\) 序,但这种做法无法处理深度

  2. 我们按照深度加点(可以通过 \(bfs\) 实现),对于加到的每一个点,寻找和它颜色相同的点的 \(dfs\) 序,记录前趋和后继( \(set\) ),
    将这个点和前趋,和后继的 \(lca\) 权值减 \(1\),将前趋和后继的 \(lca\) 权值加 \(1\)。

至于如何处理深度,可以维护一棵可持久化线段树,对于每一层在 \(dfs\) 序上建立,查询时直接区间查询相应深度的那棵线段树。

Code
#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    template<typename T>inline void read(T &x) {
        ri f=1;x=0;register char ch=gc();
        while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        x=f?x:-x;
    }
}
using IO::read;
namespace nanfeng{
    #define pb(x) push_back(x)
    #define cmax(x,y) ((x)>(y)?(x):(y))
    #define cmin(x,y) ((x)>(y)?(y):(x))
    #define FI FILE *IN
    #define FO FILE *OUT
    static const int N=1e5+7;
    set<int> ste[N];
    set<int>::iterator it,ti;
    int first[N],col[N],l[N],r[N],bc[N],que[N],head[N],st[N<<1][19],dep[N],mxdep[N],lg[N<<1],ol,dfn,t=1,n,m;
    struct edge{int v,nxt;}e[N];
    inline void add(int u,int v) {e[t].v=v,e[t].nxt=first[u],first[u]=t++;}
    struct Seg{
        #define ls(x) T[x].l
        #define rs(x) T[x].r
        #define up(x) T[x].w=T[ls(x)].w+T[rs(x)].w
        struct segmenttree{int l,r,w;}T[N<<6];
        int rt[N],tot;
        inline int New(int pre) {T[p(tot)]=T[pre];return tot;}
        void update(int &x,int p,int k,int l,int r) {
            if (!x) x=p(tot);
            if (l==r) {T[x].w+=k;return;}
            int mid(l+r>>1);
            if (p<=mid) update(ls(x),p,k,l,mid); 
            else update(rs(x),p,k,mid+1,r);
            up(x);
        }
        int merge(int x,int y) {
            if (!x||!y) return (x|y);
            T[x].w+=T[y].w;
            ls(x)=merge(ls(x),ls(y));
            rs(x)=merge(rs(x),rs(y));
            return x;
        }
        int query(int x,int l,int r,int lt,int rt) {
            if (!x) return 0;
            if (l<=lt&&rt<=r) return T[x].w;
            int mid(lt+rt>>1),res(0);
            if (l<=mid) res+=query(ls(x),l,r,lt,mid);
            if (r>mid) res+=query(rs(x),l,r,mid+1,rt);
            return res;
        }
    }T;
    void dfs(int x) {
        bc[l[x]=p(dfn)]=x;
        head[st[p(ol)][0]=x]=ol;
        mxdep[x]=dep[x];
        for (ri i(first[x]),v;i;i=e[i].nxt) 
            dep[v=e[i].v]=dep[st[p(ol)][0]=x]+1,dfs(v),mxdep[x]=cmax(mxdep[x],mxdep[v]);
        r[x]=dfn;
    }
    inline void init_rmq() {
        dep[1]=1;dfs(1);
        for (ri i(2);i<=ol;p(i)) lg[i]=lg[i>>1]+1;
        int k=lg[ol];
        for (ri j(1);j<=k;p(j)) {
            ri len=(1<<j);
            for (ri i(1);i+len-1<=ol;p(i)) {
                int x1=st[i][j-1],x2=st[i+(1<<j-1)][j-1];
                st[i][j]=dep[x1]<dep[x2]?x1:x2;
            }
        }
    }
    inline int Getlca(int u,int v) {
        if (head[u]>head[v]) swap(u,v);
        int k=lg[head[v]-head[u]+1];
        int x1=st[head[u]][k],x2=st[head[v]-(1<<k)+1][k];
        return dep[x1]<dep[x2]?x1:x2;
    }
    inline void bfs() {
        ri hd=1,tl=0,mxd;
        que[p(tl)]=1;
        while(hd<=tl) {
            ri x=que[hd++],cl=col[x],pre=0,nxt=0;
            T.update(T.rt[dep[x]],l[x],1,1,n);
            ste[cl].insert(l[x]);
            it=ti=ste[cl].find(l[x]);
            if (ti!=ste[cl].begin()) {
                pre=bc[*--ti];
                T.update(T.rt[dep[x]],l[Getlca(pre,x)],-1,1,n);
            } 
            if (it!=--ste[cl].end()) {
                nxt=bc[*p(it)];
                T.update(T.rt[dep[x]],l[Getlca(x,nxt)],-1,1,n);
            }
            if (pre&&nxt) T.update(T.rt[dep[x]],l[Getlca(pre,nxt)],1,1,n);
            for (ri i(first[x]);i;i=e[i].nxt) que[p(tl)]=e[i].v; 
        }
        mxd=dep[que[tl]];
        for (ri i(2);i<=mxd;p(i)) T.merge(T.rt[i],T.rt[i-1]);
    }
    inline int main() {
        // FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        read(n),read(m);
        for (ri i(1);i<=n;p(i)) read(col[i]);
        for (ri i(2),u;i<=n;p(i)) read(u),add(u,i);
        init_rmq();
        bfs();
        for (ri i(1),x,d;i<=m;p(i)) {
            read(x),read(d);
            if (dep[x]+d>mxdep[x]) 
                printf("%d\n",T.query(T.rt[mxdep[x]],l[x],r[x],1,n));
            else printf("%d\n",T.query(T.rt[dep[x]+d],l[x],r[x],1,n));
        }
        return 0;
    } 
}
int main() {return nanfeng::main();}
上一篇:CF645A Amity Assessment 题解


下一篇:[算法] 高斯消元详解