zoukankan      html  css  js  c++  java
  • SPOJ

    题意;

      一棵N个节点的树,有点权。M次询问,每次询问点(u,v)路径上有多少个权值不同的点。

    题解:

      树上开莫队,分块方法可以参照BZOJ1086题的方式。按照询问点(u,v)所在块将询问进行排序。更新路径时用vis数组标记路径上的点是否访问过。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 4e4+10;
    int n, m;
    int u, v;
    int a[maxn], w[maxn], c[maxn];
    int depth[maxn];
    int num[maxn];
    int f[maxn], fa[maxn], vis[maxn], lca_[maxn*3];
    int blk, tot, top, s[maxn], bel[maxn];
    int no, now_u, now_v, la_u, la_v, la_lca;
    int ans[maxn*3];
    vector<int> g[maxn];
    struct node {
        int to, id;
        node(int a, int b) {
            to = a; id = b;
        }
    };
    vector<node> q[maxn];
    void add_edge(int u, int v) {
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int find(int x) {
        return x==f[x]?x:f[x] = find(f[x]);
    }
    struct ask {
        int l, r, id;
        ask(int a, int b, int c) {
            l = a; r = b; id = c;
        }
        ask() {}
        bool operator < (const ask &a)const {
            if(bel[l]==bel[a.l]) return bel[r] < bel[a.r];
            return bel[l] < bel[a.l];
        } 
    };
    ask as[maxn*3];
    void dfs(int u, int pre, int d) {
        fa[u] = pre;
        depth[u] = d;
        int tmp = top;
        int len = g[u].size();
        for(int i = 0; i < len; i++) {
            if(g[u][i]==pre) continue;
            dfs(g[u][i], u, d+1);
                if(top-tmp >= blk) {
                  tot++;
                while (top != tmp) bel[s[top--]] = tot;
            }
        }
        s[++top] = u;
    }
    void tarjan(int u, int pre) {
        int len = g[u].size();
        for(int i = 0; i < len; i++) {
            int v = g[u][i];
            if(v==pre) continue;
            tarjan(v, u);
            f[v] = u;
        }
        vis[u] = 1;
        int lenn = q[u].size();
        for(int i = 0; i < lenn; i++) {
            int v = q[u][i].to;
            if(vis[v]) lca_[q[u][i].id] = find(v);
        } 
    }
    void xornode(int x) {
        if(vis[x]) {
            vis[x]--;
            num[a[x]]--;
            if(!num[a[x]]) no--;
        }
        else {
            vis[x]++;
            if(!num[a[x]]) no++;
            num[a[x]]++;
        }
    }
    void xorpath(int u, int u_to) {
        if(depth[u] < depth[u_to]) swap(u, u_to);
        while(depth[u] > depth[u_to]) {
            xornode(u);
            u = fa[u];
        }
        while(u != u_to) {
            xornode(u);
            xornode(u_to);
            u = fa[u];
            u_to = fa[u_to];
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) {
            f[i] = i;
            scanf("%d", &w[i]);
            c[i] = w[i];
        }
        sort(c+1, c+n+1);
        int num = unique(c+1, c+n+1)-c;
        for(int i = 1; i <= n; i++) a[i] = lower_bound(c+1, c+num, w[i])-c;
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            add_edge(u, v);
        }
        blk = sqrt(n);
        dfs(1, 0, 0);
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            if(bel[u] > bel[v]) swap(u, v);
            q[u].push_back(node(v, i));
            q[v].push_back(node(u, i));
            as[i] = ask(u, v, i);
        }
        sort(as+1, as+m+1);
        tarjan(1, 0);
        memset(vis, 0, sizeof(vis));
        la_u = la_v = la_lca = 1; xornode(1);
         for(int i = 1; i <= m; i++) {
            xorpath(as[i].l, la_u);
            xorpath(as[i].r, la_v);
            xornode(la_lca);
            xornode(lca_[as[i].id]);
            la_u = as[i].l; la_v = as[i].r; la_lca = lca_[as[i].id];
            ans[as[i].id] = no;
        }
        for(int i = 1; i <= m; i++) printf("%d
    ", ans[i]);
    }
    View Code
  • 相关阅读:
    接口和抽象类的异同点
    实体对象间传值克隆
    什么是反射&反射的8个类的用法
    ERP中反射的两个实例
    基础02 Java 跨平台原理
    基础01 dos命令
    lists删除
    多字段 java对象排序
    Java对象排序
    MySQL表中数据的迁移
  • 原文地址:https://www.cnblogs.com/Pneuis/p/8971898.html
Copyright © 2011-2022 走看看