• 【BZOJ】P3772 精神污染


    DFS序+主席树

    其实这还可以用树状数组搞的(伟大的XSH大佬提出的)
    But,本人苦调3个多小时,调不出来,最后无奈一查题解——woc,主席树!
    暴力一发,A了。。。
    那么来看看主席树是怎么PC过去的。

    维护什么?

    • 首先,想一下若路径A能被路径B包含,那么A的两端点就在路径B上。(无需讨论链和折线的情况)
    • 那么,对于每个路径一端点开个vector,把另一端点加入其中。
    • 然后,主席树上,我们就储存下A路径,查找时就看一下有多少条可以被所查路径包含。
    • 这样,主席树就很好维护了。每个节点先以父亲节点为前缀构建,维护每条路径中的另一端点,(注意了,由于这是以父亲节点为前缀的,那么祖先存的路径中一端点已经被当前节点包含了)
    • 由于需要把树转换成区间,我们需要用出入栈序(回溯时序号也要+1)

    怎样修改?

    那么,加入一端点时,只有在其子树中的点才能包含其(不需要讨论链的情况)。因此,将in[x]++,out[x]--。(单点修改)

    怎样查询

    • 查询时,由于每个节点的主席树是维护到根节点的,可以先把所查路径变成两条链(x,LCA(x,y))和(y,LCA(x,y))两部分。
    • 再对于每个链(a,b),那么其的值就是Query(x,a,b)+Query(y,a,b)-Query(LCA(x,y),a,b)-Query(pre_LCA(x,y),a,b)(Query(t,a,b)表示在t节点的主席树上,查询链(a,b))。
      注意:这里不要混淆了。链(a,b)表示一个区间,我们需要在以t节点的主席树上查询有多少个点在此区间中(即使是链(x,LCA(x,y)),其中在以y节点的主席树上也有节点,因为两者是不等价的。另外,查询链需要用到作差法)

    这样,这道题差不多就解决了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    const int MAXN=2e5+20;
    using namespace std;
    int n,m,rt[MAXN],lson[MAXN*20],rson[MAXN*20],L[MAXN],R[MAXN],mark,dfsn,lg[MAXN],pre[MAXN][20],deep[MAXN],Askx[MAXN],Asky[MAXN];
    ll sum[MAXN*20],ans;
    vector<int> G[MAXN],A[MAXN];
    void DFS_BL(int x,int fa){
        L[x]=++dfsn;
        pre[x][0]=fa;
        deep[x]=deep[fa]+1;
        for(int i=1;(1<<i)<=deep[x];i++)pre[x][i]=pre[pre[x][i-1]][i-1];
        for(int i=0;i<G[x].size();i++){
            int t=G[x][i];
            if(t==fa)continue;
            DFS_BL(t,x);
        }
        R[x]=++dfsn;
    }
    int LCA(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        while(deep[x]>deep[y])x=pre[x][lg[deep[x]-deep[y]]-1];
        if(x==y)return x;
        for(int k=lg[deep[x]]-1;k>=0;k--){
            if(pre[x][k]==pre[y][k])continue;
            x=pre[x][k],y=pre[y][k];
        }
        return pre[x][0];
    }
    void insert(int &node,int ot,int L,int R,int num,int pos){
        node=++mark;
        sum[node]=sum[ot]+num;
        lson[node]=lson[ot];
        rson[node]=rson[ot];
        if(L==R)return;
        int mid=(L+R)>>1;
        if(pos<=mid)insert(lson[node],lson[ot],L,mid,num,pos);
        else insert(rson[node],rson[ot],mid+1,R,num,pos);
    }
    ll query(int nodex,int nodey,int nodef,int nodeff,int L,int R,int st,int ed){
        if(st==L&&ed==R)return sum[nodex]+sum[nodey]-sum[nodef]-sum[nodeff];
        int mid=(L+R)>>1;
        if(ed<=mid)return query(lson[nodex],lson[nodey],lson[nodef],lson[nodeff],L,mid,st,ed);
        else if(st>=mid+1)return query(rson[nodex],rson[nodey],rson[nodef],rson[nodeff],mid+1,R,st,ed);
        else return query(lson[nodex],lson[nodey],lson[nodef],lson[nodeff],L,mid,st,mid)+query(rson[nodex],rson[nodey],rson[nodef],rson[nodeff],mid+1,R,mid+1,ed);
    }
    void DFS(int x,int fa){
        rt[x]=rt[fa];
        int tmp;
        for(int i=0;i<A[x].size();i++){
            insert(tmp,rt[x],1,dfsn,1,L[A[x][i]]);
            rt[x]=tmp;
            insert(tmp,rt[x],1,dfsn,-1,R[A[x][i]]);
            rt[x]=tmp;
        }
        for(int i=0;i<G[x].size();i++){
            int t=G[x][i];
            if(t==fa)continue;
            DFS(t,x);
        }
    }
    int main(){
        for(int i=1;i<=MAXN-10;i++)lg[i]=lg[i-1]+((1<<lg[i-1])==i);
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n-1;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        DFS_BL(1,0);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            Askx[i]=x,Asky[i]=y;
            A[x].push_back(y);
        }
        DFS(1,0);
        for(int i=1;i<=m;i++){
            int x=Askx[i],y=Asky[i];
            int lca=LCA(x,y);
            ans+=query(rt[x],rt[y],rt[lca],rt[pre[lca][0]],1,dfsn,L[lca],L[x]);
            ans+=query(rt[x],rt[y],rt[lca],rt[pre[lca][0]],1,dfsn,L[lca],L[y]);
            ans-=query(rt[x],rt[y],rt[lca],rt[pre[lca][0]],1,dfsn,L[lca],L[lca]);
            ans--;
        }
        ll tot=1LL*m*(m-1)/2;
        ll gcd=__gcd(tot,ans);
        printf("%lld/%lld",ans/gcd,tot/gcd);
        return 0;
    }
    
    
  • 相关阅读:
    docker初识--简单用法
    性能测试--面向目标场景设计
    性能测试之--波浪场景设计
    性能测试之--阶梯负载场景设计
    Jmeter后置处理器之正则提取器详解
    JMETE-元件执行顺序
    python高阶函数-map、reduce、filter
    socket 多线程安全、粘包问题
    The fastest MySQL Sandbox setup ever!
    两个实用的Python的装饰器
  • 原文地址:https://www.cnblogs.com/SillyTieT/p/11197856.html
Copyright © 2020-2023  润新知