HDU 4366 Successor 分块做法

http://acm.hdu.edu.cn/showproblem.php?pid=4366

今日重新做了这题的分块,果然是隔太久了,都忘记了。。

首先,用DFS序变成一维的问题

关键是它有两个权值,该如何处理呢?

首先假设我们的DFS序列是List,

那么,对其进行分块。对于每一个块,先按能力排序,用数组tosort[]保存,这样我就可以用O(magic)的时间,就是扫一次这个块,维护出一个数组,mx[i]表示大于等于tosort[i].ablity时,最大的忠诚度。

那么我查询的时候,就可以,如果不在块里的,暴力,否则,因为每一个块已经排好序,那么我可以二分出一个位置,找到第一个能力值大于等于所查询的val,那么mx[pos]是答案,因为mx[pos]就表示大于等于这个位置的能力值,所拥有的最大忠诚度。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 50000 + 20;
struct Edge {
    int u, v, w;
    int tonext;
}e[2 * maxn];
int num;
int first[maxn + 20];
int getid[1000000 + 20];
struct node {
    int loy, abi;
    bool operator < (const struct node & rhs) const {
        return abi < rhs.abi;
    }
}a[maxn], List[maxn], tosort[maxn];
void addEgde(int u, int v) {
    ++num;
    e[num].u = u;
    e[num].v = v;
    e[num].tonext = first[u];
    first[u] = num;
}
int DFN;
int L[maxn], R[maxn];
bool vis[maxn];
void dfs(int cur) {
    L[cur] = DFN;
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
//        assert(vis[v] == false);
//        vis[v] = true;
        ++DFN;
        List[DFN] = tosort[DFN] = a[v];
        dfs(v);
    }
    R[cur] = DFN;
}
int magic;
int mx[maxn];
int tofind(int begin, int end, int val) {
//    cout << begin << " " << end << " ***" << endl;
    if (tosort[end].abi <= val) return -1;
    if (tosort[begin].abi > val) return mx[begin];
    while (begin <= end) {
        int mid = (begin + end) >> 1;
        if (tosort[mid].abi > val) {
            end = mid - 1;
        } else begin = mid + 1;
    }
    return mx[begin];
}
void work() {
    int n, m;
    cin >> n >> m;
    magic = (int)sqrt(n * 1.0);
    for (int i = 1; i <= n - 1; ++i) {
        int fa;
        cin >> fa >> a[i].loy >> a[i].abi;
        getid[a[i].loy] = i;
        addEgde(fa, i);
    }
    dfs(0);
//    for (int i = 0; i <= n - 1; ++i) {
//        cout << L[i] << " " << R[i] << endl;
//    }
    for (int i = 0; i < n; i += magic) {
        int j = i + magic;
        if (j > n) break;
        sort(tosort + i, tosort + j);
        mx[j - 1] = tosort[j - 1].loy;
        for (int k = j - 2; k >= i; --k) {
            if (tosort[k].loy < mx[k + 1]) {
                mx[k] = mx[k + 1];
            } else mx[k] = tosort[k].loy;
        }
//        for (int k = i; k < i + magic; ++k) {
//            cout << mx[k] << endl;
//        }
    }
    while (m--) {
        int id;
        cin >> id;
        int val = a[id].abi;
        int begin = L[id], end = R[id];
//        cout << begin << " " << end << " ***" << endl;
        int ans = -1;
        for (int i = begin + 1; i <= end;) {
            if (i % magic == 0 && i + magic <= end) {
                ans = max(ans, tofind(i, i + magic - 1, val));
                i += magic;
            } else {
                if (List[i].abi > val && ans < List[i].loy) {
                    ans = List[i].loy;
                }
                ++i;
            }
        }
        if (ans == -1) {
            cout << -1 << endl;
        } else cout << getid[ans] << endl;
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    IOS;
    a[0].abi = a[0].loy = -1;
    List[0] = tosort[0] = a[0];
    int t;
    cin >> t;
    while (t--) {
        DFN = 0;
        num = 0;
        memset(mx, -1, sizeof mx);
        memset(first, 0, sizeof first);
        work();
    }
    return 0;
}
时间: 2024-08-07 18:52:45

HDU 4366 Successor 分块做法的相关文章

HDU 4366 Successor(线段树 DFS时间戳啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4366 Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2961    Accepted Submission(s): 689 Problem Description Sean owns a company and he

hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the h

HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护

给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示dfs序,则R[i] - L[i] + 1 就是当前i这个节点拥有的子孙个数. 对于一颗树,dfs的时候,访问节点有先后顺序,那么可以用一个struct node List[maxn];表示这课树中访问的先后顺序. 例如这颗树,我假设是先访问0 --> 3 --> 2 ---> 4 ---&g

HDU 4366 Successor

Successor Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 436664-bit integer IO format: %I64d      Java class name: Main Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has

HDU 4366 Successor( DFS序+ 线段树 )

Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2631    Accepted Submission(s): 634 Problem Description Sean owns a company and he is the BOSS.The other Staff has one Superior.every st

Successor HDU - 4366 分块

代码+注释: 1 /* 2 题意: 3 一共有n个人,其中0号是总裁(金字塔顶尖).后面输入其他n-1个人的信息啊a.b.c,分别代表第i个人的上级是a,他的 4 忠诚度为b,他的能力为c.后面有m次询问.他问你能不能找到一个能力比他高的,且忠诚度最高的人.(注意能力只需要 5 大于此人就可以,不需要最高) 6 7 8 题解: 9 这道题目用的是分块的方法 10 11 首先需要跑一遍dfs来确定每一个人所处于金字塔的位置.从总裁开始向他的下属跑dfs(注意是dfs不是bfs) 12 因为这样我们

【分块】 HDU 4336 Successor

通道 题意:给一个树,树上每个节点都有两个属性:忠诚度和能力,给出若干查询,求每个子树中能力 > 树根能力的点中,忠诚度最高的那个 思路:子树dfs序即可,然后忠诚度排个序,取能力值大于u且忠诚度最高的,虽然线段树也可以搞,练练分块. 代码: #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <vector> #include <map&g

hdu 1754 I Hate It(分块做法)

题意:中文题,不多解释 思路:这个题原本用线段树很容易做,但分块其实也很容易,对于分块的复杂度还不是很会计算,只知道是每次分为sqrt(n)块,然后一共有sqrt(n)块,其他地方直接暴力,这应该是hzw大牛里的第一类最简单的分块(跑的好像比线段树慢很多) 代码: #include <bits/stdc++.h> using namespace std; const int maxn=2e5+7; int n,m; int block,a[maxn],num[maxn],maxe[maxn];

POJ2104 K-th Number [分块做法]

传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求>=v的有几个 既然一个数v的名次可以求,我们二分这个数就行了啊 然而...... 首先,你二分到的这个数不一定在区间里出现过 比如 1 2 5 8 9 4和5的名次都是3 于是,我修改了某个区间名次的定义: “如果一个数的名次是x,但是区间中没有次数,那么他的名次为x-1” 实现上只需要find里