hdu 6162(Treap)

离线处理所有请求对于每一个点,求这个点到根的[a, b]的总和,即比b+1小的总和减去比a小的总和,因此对于每一个请求我们将其分为三个查询,分别为s的总和,t的总和,以及lca(s,t)的总和,容斥一下就可以得到s到t的总和,事先将这些点存储在一个数组里,dfs到这个点的时候我们用Treap动态维护一下,用Treap查询比某个数小的总和。

#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>
#include <time.h>
#include <iostream>
using namespace std;
const int maxn = 100005;
const int maxm = 20;
int c[maxn];
vector<int> G[maxn];
struct Node
{
    Node *ch[2];
    int r, v, num;
    long long s;
    int cmp(int x) const
    {
        if(x == v)
            return -1;
        return x < v ? 0 : 1;
    }
    void maintain()
    {
        s = 1LL * v * num;
        if(ch[0] != NULL)
            s += ch[0]->s;
        if(ch[1] != NULL)
            s += ch[1]->s;
    }
};
Node *root;
struct Edge
{
    int to, next;
}edge[maxn * 2];
int head[maxn], tot;
void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
int fa[maxn][maxm];
int deg[maxn];

void BFS(int root)
{
    queue<int> que;
    deg[root] = 0;
    fa[root][0] = root;
    que.push(root);
    while(!que.empty())
    {
        int tmp = que.front(); que.pop();
        for(int i = 1; i < maxm; ++i)
        {
            fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
        }
        for(int i = head[tmp]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == fa[tmp][0])
                continue;
            deg[v] = deg[tmp] + 1;
            fa[v][0] = tmp;
            que.push(v);
        }
    }
}
int LCA(int u, int v)
{
    if(deg[u] > deg[v])
        swap(u, v);
    int hu = deg[u], hv = deg[v];
    int tu = u, tv = v;
    for(int det = hv - hu, i = 0; det; det >>= 1, ++i)
        if(det & 1)
            tv = fa[tv][i];
    if(tu == tv)
        return tu;
    for(int i = maxm - 1; i >= 0; --i)
    {
        if(fa[tu][i] == fa[tv][i])
            continue;
        tu = fa[tu][i];
        tv = fa[tv][i];
    }
    return fa[tu][0];
}
void Rotate(Node* &o, int d)
{
    Node *k = o->ch[d ^ 1]; o->ch[d ^ 1] = k->ch[d]; k->ch[d] = o;
    o->maintain(); k->maintain(); o = k;
}
void Insert(Node* &o, int x)
{
    if(o == NULL)
    {
        o = new Node(); o->ch[0] = o->ch[1] = NULL; o->v = x; o->r = rand(); o->s = o->v; o->num = 1;
    }
    else
    {
        int d = o->cmp(x);
        if(d == -1)
        {
            o->s += x;
            o->num += 1;
            return ;
        }
        Insert(o->ch[d], x); if(o->ch[d]->r > o->r) Rotate(o, d ^ 1);
    }
    o->maintain();
}
void Remove(Node* &o, int x)
{
    int d = o->cmp(x);
    if(d == -1)
    {
        if(o->num != 1)
        {
            o->num -= 1;
            o->s -= x;
            return ;
        }
        Node *u = o;
        if(o->ch[0] == NULL) {o = o->ch[1]; delete u;}
        else if(o->ch[1] == NULL) {o = o->ch[0]; delete u;}
        else
        {
            int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0);
            Rotate(o, d2); Remove(o->ch[d2], x);
        }
    }
    else
        Remove(o->ch[d], x);
    if(o != NULL) o->maintain();
}
long long Rank(Node *u, int x)
{
    if(u == NULL)
        return 0;
    else if(x == u->v)
    {
        return u->ch[0] == NULL ? 0 : u->ch[0]->s;
    }
    else
    {
        int d = u->cmp(x);
        if(d == 0)
            return Rank(u->ch[d], x);
        else
            return (u->ch[0] == NULL ? 0 : u->ch[0]->s) + 1LL * u->v * u->num + Rank(u->ch[d], x);
    }
}
void print(Node *u, int d)
{
    if(u == NULL)
        return ;
    cout << "d == " << d << endl;
    cout << "tmp_v == " << u->v << endl;
    cout << "tmp_s == " << u->s << endl;
    print(u->ch[0], 0);
    print(u->ch[1], 0);
}
void del(Node *u)
{
    if(u == NULL)
        return ;
    if(u->ch[0] != NULL)
    {
        del(u->ch[0]);
    }
    if(u->ch[1] != NULL)
    {
        del(u->ch[1]);
    }
    delete u;
}
struct Item
{
    int a, b, v, id;
    Item(int a, int b, int v, int id) : a(a), b(b), v(v), id(id) { }
};
vector<Item> que[maxn];
long long ans[maxn];
void dfs(int u, int father)
{
    Insert(root, c[u]);
//    print(root, 0);
    for(int i = 0; i < que[u].size(); ++i)
    {
        int a = que[u][i].a;
        int b = que[u][i].b;
        int id = que[u][i].id;
        int v = que[u][i].v;
        ans[id] += v * (Rank(root, b + 1) - Rank(root, a));
        if(c[u] <= b && c[u] >= a && v < 0)
            ans[id] += c[u];
//        cout << Rank(root, b + 1) << " " << Rank(root, a) << endl;
//        cout << "u == " << u << endl;
//        cout << "id == " << id << endl;
//        cout << "ans == " << ans[id] << endl;
    }
    for(int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i];
        if(v != father)
            dfs(v, u);
    }
    Remove(root, c[u]);
}
int main()
{
//    freopen("1002.in", "r", stdin);
//    freopen("233.out", "w", stdout);
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        init();
        for(int i = 1; i <= n; ++i)
        {
            G[i].clear();
            que[i].clear();
        }
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &c[i]);
        }
        for(int i = 0; i < n - 1; ++i)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
            addedge(u, v);
            addedge(v, u);
        }
        BFS(1);
        for(int i = 0; i < m; ++i)
        {
            int s, t, a, b;
            scanf("%d%d%d%d", &s, &t, &a, &b);
            int l = LCA(s, t);
            que[l].push_back(Item(a, b, -2, i));
            que[s].push_back(Item(a, b, 1, i));
            que[t].push_back(Item(a, b, 1, i));
//            cout << "l == " << l << " s == " << s << " t == " << t << endl;
        }
        memset(ans, 0, sizeof(ans));
        root = NULL;
        dfs(1, -1);
        del(root);
        for(int i = 0; i < m; ++i)
        {
            printf("%I64d%c", ans[i], " \n"[i == m - 1]);
        }
    }
    return 0;
}
/*
10 10
241 3873 7875 8445 7001 3861 245 1641 3277 2790
2 1
3 2
4 1
5 3
6 5
7 3
8 7
9 5
10 6
9 5 1213 8766
1 5 1776 9931
5 2 5099 7343
4 1 969 6636
10 5 5361 5985
3 6 6963 8056
6 1 2159 8721
5 5 3843 6771
7 5 2009 7985
1 7 4797 4861
*/

时间: 2024-10-26 19:50:40

hdu 6162(Treap)的相关文章

hdu 6162 Ch’s gift(树链剖分+主席树)

题目链接:hdu 6162 Ch's gift 题意: 给你一棵树,树上每个点有一个权值,现在有m个询问,每次询问给你一个s,t,L,R,问你从s到t的路径上,权值在[L,R]内的总和为多少. 题解: 我感觉我写复杂了,用树链剖分来维护路径,然后用主席树来建立权值线段树乱搞. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);

L - Ch’s gift HDU - 6162

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2534    Accepted Submission(s): 887 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6162 Problem Description Mr. Cui is working off-campu

HDU 6162 Ch’s gift (线段树+树链剖分)

题意:给定上一棵树,每个树的结点有一个权值,有 m 个询问,每次询问 s, t ,  a, b,问你从 s 到 t 这条路上,权值在 a 和 b 之间的和.(闭区间). 析:很明显的树链剖分,但是要用线段树来维护,首先先离线,然后按询问的 a 排序,每次把小于 a 的权值先更新上,然后再查询,这样就是区间求和了,算完小于a的,再算b的,最答案相减就好了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #inc

HDU 6162 Ch’s gift (树剖 + 离线线段树)

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 662    Accepted Submission(s): 229 Problem Description Mr. Cui is working off-campus and he misses his girl friend very much. After a wh

hdu 4006 Treap

继续测模板... 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <ctime> 6 using namespace std; 7 8 struct Node 9 { 10 Node * ch[2]; 11 int v, r, size, cnt; 12 int cmp( int x ) 13 { 14 i

HDU 6162 树链剖分

题意:给你一颗树,每个节点有有一个权值,每次询问从x到y的最短路上权值在c到d之间的所有的点的权值和是多少. 思路:肯定要用树剖,因为询问c到d之间这种操作树上倍增很难做,但是用其它数据结构可以比较好的查询.我们可以用线段树来进行这种操作.每次询问一个区间时,如果当前区间被查询区间完全覆盖,并且区间里的最大指小于等于d,最小值大于等于c,才返回,否则继续查询.这种做法其实可以被卡掉,比如很长的路径上点权都是1, 2, 1, 2这种,而询问的c和d都是1,这样线段树上的询问会被卡成O(n)的.我感

Treap树模板hdu-4585

目录 例题:hdu 4585 Treap树 1.Treap树的唯一性 2.Treap树的平衡问题 3.Treap树的数据结构 4.Treap树的插入 5.插入过程中维护堆的过程中用到的旋转 6.寻找第k大的数 O(logn) 7.查询某个数的名次 O(logn) 8.hdu 4585 AC代码 例题:hdu 4585 Treap树 是一种简单的平衡二叉搜索树. 二叉搜索树的每一个节点都有一个键值,除此之外Treap树为每个节点人为添加了一个称之为优先级的权值.对于键值来说,这是一棵二叉搜索树,对

HDU 4006 求第k大数 treap

裸题,瞬秒.. #include <stdio.h> #include <iostream> #include <algorithm> #include <math.h> #include <vector> #include <set> #include <map> #include <queue> using namespace std; #define L(id) tree[id].ch[0] #defin

HDU 3726 Graph and Queries treap树

题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node(int v): v(v) { ch[0] = ch[1] = NULL; r = rand(); s