zoukankan      html  css  js  c++  java
  • [ZJOI2019]语言(树链剖分+动态开点线段树+启发式合并)

    首先,对于从每个点出发的路径,答案一定是过这个点的路径所覆盖的点数。然后可以做树上差分,对每个点记录路径产生总贡献,然后做一个树剖维护,对每个点维护一个动态开点线段树。最后再从根节点开始做一遍dfs,把每个节点对应的线段树启发式合并即可。时空复杂度均为O(nlog2n)。听说还有一个log的做法,但感觉太神仙不会,不过2个log能过就不管了。

    #include<bits/stdc++.h>
    #define lson l,mid,tr[rt].lc
    #define rson mid+1,r,tr[rt].rc
    using namespace std;
    const int N=1e5+7;
    struct Seg{int lc,rc,tag,sz;}tr[N*300];
    int n,m,cnt,fa[N],sz[N],dep[N],son[N],top[N],dfn[N],rt[N];
    long long ans;
    vector<int>G[N];
    void dfs1(int u,int f)
    {
        sz[u]=1,dep[u]=dep[f]+1,fa[u]=f;
        for(int i=0;i<G[u].size();i++)
        if(G[u][i]!=f)
        {
            dfs1(G[u][i],u),sz[u]+=sz[G[u][i]];
            if(sz[son[u]]<sz[G[u][i]])son[u]=G[u][i];
        }
    }
    void dfs2(int u,int tp)
    {
        top[u]=tp,dfn[u]=++cnt;
        if(son[u])dfs2(son[u],tp);
        for(int i=0;i<G[u].size();i++)if(G[u][i]!=fa[u]&&G[u][i]!=son[u])dfs2(G[u][i],G[u][i]);
    }
    void pushup(int rt,int len)
    {if(tr[rt].tag)tr[rt].sz=len;else tr[rt].sz=tr[tr[rt].lc].sz+tr[tr[rt].rc].sz;}
    void modify(int rt,int v,int len){tr[rt].tag+=v;pushup(rt,len);}
    void update(int L,int R,int v,int l,int r,int&rt)
    {
        if(!rt)rt=++cnt;
        if(L<=l&&r<=R){modify(rt,v,r-l+1);return;}
        int mid=l+r>>1;
        if(L<=mid)update(L,R,v,lson);
        if(R>mid)update(L,R,v,rson);
        pushup(rt,r-l+1);
    }
    void Update(int&rt,int x,int y,int v)
    {
        while(top[x]!=top[y])update(dfn[top[x]],dfn[x],v,1,n,rt),x=fa[top[x]];
        if(x!=y)update(dfn[y]+1,dfn[x],v,1,n,rt);
    }
    int lca(int x,int y)
    {
        while(top[x]!=top[y])if(dep[top[x]]<dep[top[y]])y=fa[top[y]];else x=fa[top[x]];
        return dep[x]<dep[y]?x:y;
    }
    int merge(int u,int v,int l,int r)
    {
        if(!u||!v)return u+v;
        tr[u].tag+=tr[v].tag;
        if(l==r){pushup(u,1);return u;}
        int mid=l+r>>1;
        tr[u].lc=merge(tr[u].lc,tr[v].lc,l,mid);
        tr[u].rc=merge(tr[u].rc,tr[v].rc,mid+1,r);
        pushup(u,r-l+1);
        return u;
    }
    void dfs3(int u,int f)
    {
        for(int i=0;i<G[u].size();i++)
        if(G[u][i]!=f)dfs3(G[u][i],u),rt[u]=merge(rt[u],rt[G[u][i]],1,n);
        ans+=max(tr[rt[u]].sz-1,0);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
        dfs1(1,0);
        dfs2(1,1);
        cnt=0;
        for(int i=1,x,y,f;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            f=lca(x,y);
            Update(rt[x],x,fa[f],1),Update(rt[x],y,f,1);
            Update(rt[y],x,fa[f],1),Update(rt[y],y,f,1);
            Update(rt[f],x,fa[f],-1),Update(rt[f],y,f,-1);
            if(fa[f])Update(rt[fa[f]],x,fa[f],-1),Update(rt[fa[f]],y,f,-1);
        }
        dfs3(1,0);
        cout<<ans/2;
    }
    View Code
  • 相关阅读:
    利用相关的Aware接口
    java 值传递和引用传递。
    权限控制框架Spring Security 和Shiro 的总结
    优秀代码养成
    Servlet 基础知识
    leetcode 501. Find Mode in Binary Search Tree
    leetcode 530. Minimum Absolute Difference in BST
    leetcode 543. Diameter of Binary Tree
    leetcode 551. Student Attendance Record I
    leetcode 563. Binary Tree Tilt
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10816748.html
Copyright © 2011-2022 走看看