zoukankan      html  css  js  c++  java
  • SP10707 COT2

    参考博客

    对于树上的路径询问问题

    • O(1)的时间加入或删除一个点的贡献 -> (O(nsqrt n))的复杂度求出所有询问的答案

    对树上的结点进行分块,离线询问后排序,顺序遍历暴力转移路径(转移时加入或删除路径上的点的贡献即可)。

    关于转移路径:首先定义路径:设(T_u)(u) 到根的路径上边的集合,那么(u)(v) 的路径上的边的集合就是(T_u riangle T_v) (( riangle) 是对称差)。要从(u ightarrow v) 转移到 (u' ightarrow v') 等价于

    [T_u riangle T_v ightarrow T_{u'} riangle T_{v'} ]

    根据对称差的性质(T_u riangle T_u riangle T_{u'} = T_{u'}) 所以只需要:

    [T_u riangle T_v riangle (T_u riangle T_{u'}) riangle (T_v riangle T_{v'}) = T_{u'} riangle T_{v'} ]

    体现在程序上就是从(u ightarrow v) 转移到(u' ightarrow v')时,暴力遍历路径(u ightarrow u')和路径(v ightarrow v')上的边,如果一条边已经加入,那么删除它,如果没有加入,就加入它。这样就完成了对称差运算。

    复杂度分析:设树分块大小为S,每次转移(u ightarrow u')在块内的转移路径长度是(O(S))的,而(v ightarrow v')的转移可以按照(dfs)序来递增,这样复杂度就是(O(ms+{n^2over S}))

    (S=sqrt n)时最优

    例题 题目传送门

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 40010;
    const int M = 100010;
    vector<int> G[N],alls;
    int be[N],f[N][19],n,m,ans[M],dep[N],u=1,v=1,sum[N],vis[N],a[N],base,cnt;
    int res;
    int st[N],top;
    struct Query{
        int l,r;
        int id;
    }q[M];
    void dfs(int x,int fa = -1){
        for(int i=1;i<18;i++)
            f[x][i] = f[f[x][i-1]][i-1];
        int bottom = top;
        for(int i = 0;i<G[x].size();i++){
            int y = G[x][i];
            if(y == fa)continue;
            dep[y] = dep[x] + 1;
            f[y][0] = x;
            dfs(y,x);
            if(top - bottom >= base){
                cnt++;
                while(top != bottom){
                    be[st[top--]] = cnt;
                }
            }
        }
        st[++top] = x;
    }
    bool cmp(Query a,Query b){
        return be[a.l] == be[b.l] ? be[a.r] < be[b.r] : be[a.l] < be[b.l];
    }
    int LCA(int x,int y){
        if(dep[x] > dep[y])swap(x,y);
        for(int i=18;i>=0;i--)if(dep[x] <= dep[f[y][i]]) y = f[y][i];
        if(x == y)return x;
        for(int i=18;i>=0;i--)if(f[x][i] != f[y][i])x = f[x][i],y = f[y][i];
        return f[x][0];
    }
    void Run(int u){
        if(vis[u] == 1){
            vis[u] = 0;
            if(--sum[a[u]] == 0)res--;
        }
        else{
            vis[u] = 1;
            if(sum[a[u]]++ == 0)res++;
        }
    }
    void move(int x,int y){
        if(dep[x] < dep[y])swap(x,y);
        while(dep[x] > dep[y])Run(x),x = f[x][0];
        while(x != y)Run(x),Run(y),x = f[x][0],y = f[y][0];
    }
    int main(){
        scanf("%d%d",&n,&m);
        base = sqrt(n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            alls.push_back(a[i]);
        }
        /*离散化*/
        sort(alls.begin(),alls.end());
        alls.erase(unique(alls.begin(),alls.end()),alls.end());
        for(int i=1;i<=n;i++){
            int id = lower_bound(alls.begin(),alls.end(),a[i]) - alls.begin() + 1;
            a[i] = id;
        }
        //存树
        for(int i=1;i<n;i++){
            int x,y;scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        dep[1] = 1;//这里如果不单独设为wa
        dfs(1);
        while(top)be[st[top--]] = cnt;
        //存询问
        for(int i=1;i<=m;i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id = i;
        }
        sort(q+1,q+1+m,cmp);
        for(int i=1;i<=m;i++){
            if(u != q[i].l){move(u,q[i].l);u=q[i].l;}
            if(v != q[i].r){move(v,q[i].r);v=q[i].r;}
            int anc = LCA(u,v);
            Run(anc);//单独考虑LCA
            ans[q[i].id] = res;
            Run(anc);//
        }
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    《理解 ES6》阅读整理:块绑定(Block Binding)
    Webpack使用教程六(Plugins)
    Webpack使用教程五(Babel)
    Webpack使用教程四(Loaders)
    Webpack使用教程三(webpack-dev-server)
    Webpack使用教程二
    Node.js、npm和webpack的安装
    Maven的安装和配置
    Java事件处理机制
    MySQL安装
  • 原文地址:https://www.cnblogs.com/1625--H/p/11329565.html
Copyright © 2011-2022 走看看