HDU 6162 - Ch’s gift | 2017 ZJUT Multi-University Training 9

/*
HDU 6162 - Ch’s gift [ LCA,线段树 ]  |  2017 ZJUT Multi-University Training 9
题意:
	N节点的树,Q组询问
	每次询问s,t两节点之间的路径上点权值在[a,b]之间的点权总和
分析:
	求出每个询问的LCA,然后离线
	按dfs顺序更新树状数组,即某点处树状数组中存的值为其所有祖先节点的值
	每个点处对答案的贡献为:
		当其为第 i 个 lca 时, ans[i] -= 2 * query(a,b) , 再特判该节点
		当其为第 i 个 s,t 时, ans[i] += query(a,b)
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+5;
typedef pair<int, int> P;
vector<int> G[N];//存边
vector<P> QQ[N];
int a[N], b[N*4], cnt, n, Q;
struct Query {
    int s, t, lca, a, b;
}q[N];
void addedge(int u, int v) {
    G[u].push_back(v);
}
namespace LCA {
    struct Query {
        int v, q;
    }; vector <Query> query[N];//存每个点的询问
    int ans[N], f[N], vis[N];
    int sf(int x) {
        return x == f[x] ? x : f[x] = sf(f[x]);
    }
    void init() {
        memset(ans, -1, sizeof(ans));
        for (int i = 0; i < N; i++) {
            vis[i] = 0; f[i] = i; query[i].clear();
        }
    }
    void adq(int u, int v, int id) {//添加询问
        query[u].push_back(Query{v, id});
        query[v].push_back(Query{u, id});
    }
    void LCA(int u) {
        f[u] = u, vis[u] = 1;
        for (auto& x : query[u]) {
            if (vis[x.v] && ans[x.q] == -1)
                ans[x.q] = sf(x.v);
        }
        for (auto& v : G[u]) {
            if (vis[v]) continue;
            LCA(v);
            f[v] = u;
        }
    }
}
void init2()
{
    cnt = 0;
    for (int i = 1; i <= n; i++) b[++cnt] = a[i];
    for (int i = 1; i <= Q; i++)
    {
        b[++cnt] = q[i].a;
        b[++cnt] = q[i].b;
    }
    sort(b+1, b+cnt+1);
    cnt = unique(b+1, b+cnt+1) - (b+1);
    for (int i = 1; i <= n; i++)
        a[i] = lower_bound(b+1, b+cnt+1, a[i]) - b;
    for (int i = 1; i <= Q; i++)
    {
        q[i].a = lower_bound(b+1, b+cnt+1, q[i].a) - b;
        q[i].b = lower_bound(b+1, b+cnt+1, q[i].b) - b;
    }
}
LL ans[N], c[N<<4];
void modify(int x, LL num){
    while (x <= cnt) c[x] += num, x += x&-x;
}
LL sum(int x) {
    LL s = 0;
    while (x) s += c[x], x -= x&-x;
    return s;
}
void init()
{
    memset(c, 0, sizeof(c));
    for (int i = 0; i < N; i++) G[i].clear();
    for (int i = 0; i < N; i++) QQ[i].clear();
    memset(ans, 0, sizeof(ans));
}
void dfs(int u, int pre)
{
    modify(a[u], b[a[u]]);
    LL tmp;
    for (auto & qq : QQ[u])
    {
        tmp = sum(q[qq.first].b) - sum(q[qq.first].a-1);
        if (qq.second == -1)
        {
            ans[qq.first] -= 2*tmp;
            if (a[u] >= q[qq.first].a && a[u] <= q[qq.first].b)
                ans[qq.first] += b[a[u]];
        }
        else
        {
            ans[qq.first] += tmp;
        }
    }
    for (auto&v: G[u])
    {
        if (v == pre) continue;
        dfs(v, u);
    }
    modify(a[u], -b[a[u]]);
}
int main()
{
    int u, v;
    while (~scanf("%d%d", &n, &Q))
    {
        init();
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i < n; i++)
        {
            scanf("%d%d", &u, &v);
            addedge(u, v); addedge(v, u);
        }
        for (int i = 1; i <= Q; i++)
            scanf("%d%d%d%d", &q[i].s, &q[i].t, &q[i].a, &q[i].b);
        init2();
        LCA::init();
        for (int i = 1; i <= Q; i++) LCA::adq(q[i].s, q[i].t, i);
        LCA::LCA(1);
        for (int i = 1; i <= Q; i++)
        {
            q[i].lca = LCA::ans[i];
            QQ[q[i].lca].push_back(P(i, -1));
            QQ[q[i].s].push_back(P(i, 1));
            QQ[q[i].t].push_back(P(i, 1));
        }
        dfs(1, 1);
        for (int i = 1; i < Q; i++) printf("%lld ", ans[i]);
        printf("%lld\n", ans[Q]);
    }
}

  

posted @ 2017-08-23 17:43  nicetomeetu  阅读(118)  评论(0编辑  收藏  举报