HDU 4776 Ants(Trie+优先队列)

Ants

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 1324    Accepted Submission(s): 289

Problem Description
  There are some apple trees in a farm. An apple tree can be described as a connected graph which has n nodes and n-1 edges. The apples are the nodes and the branches are the edges. Every edge is assigned a value denoting the length of the branch. 
  Now in the farm come a lot of ants, which are going to enjoy the delicious apples. The ants climb the tree one by one. Every ant would choose a node as the starting node and another node as the ending node, then it would crawl alone the unique path from the starting node to the ending node. The distance between two nodes is defined as the XOR sum of lengths of all the edges in the unique path between them. Every ant wants to crawl along such a path which the distance is as large as possible. But two ants cannot crawl from the same starting node to the same ending node. You should calculate the distance which the k-th ant crawled.
  Note that the starting node and the ending node cannot be the same for an ant.
 

 

Input
  The input consists of several test case.
  For each test case, the first line contain an integer n denoting the number of nodes.
  The next n-1 lines each contains three integers x,y,z, denoting that there exists an edge between node x and node y and its length is z. The nodes are numbered from 1 to n.
  The next line contain a integer m denoting the number of queries.
  In the next m lines, each line contains an integer k denoting that you need to calculate the distance of the k-th ant.
  The input ends with n = 0.
  (1 <= n, m <= 100000, 1 <= x, y <= n, 0 <= z <= 10 18, 1 <= k <= 200000)
 

 

Output
  For each query, output the answer. If such path does not exist, just output -1.
 

 

Sample Input
3
1 2 2
3 2 3
3
1
2
5
 
5
1 3 7
2 1 3
4 3 6
5 3 1
3
1
8
1000
 
0
 

 

Sample Output
3
3
1
7
6
-1
Hint
  In the first test case, the first ant may crawl from node 2 to node 3, and the second ant may crawl from node 3 to node 2, and the 5-th ant may crawl from node 1 to node 3.   The distance of the 5-th ant can be calculated by 2 xor 3 = 1.

 

 

题目链接:HDU 4776

题意就是求第K大路径异或值,那很容易想到用前缀和的思想把一条路径的异或值用DFS转换成$val[u]\oplus val[v]$,其中$val[i]$是从根节点到$i$节点的路径异或和,那么题目就变成了给定大小为N个数列$val[]$,求第K大的两两异或值$val[i]\oplus val[j]$。可以先从第1大开始求,第1大很简单,对于所有的$val[i]$,找出它能异或出的最大值$val[i]\oplus val[j]$,那么这些最大值序列中全局最大的就是第1大的值,然后考虑第2大,可以发现第2大只能来自两种情况:第1大的值对应的节点下第2大的值或者是就是原来求第1大的时候第2大的值,而第3、第4大其本身和后面的迭代结果不会成为当前的第2大,因为目前的第2大已经比后面的数都大了,对于一个节点$u$,每一次去找它的第$k+1$大的值,数值必定是递减的也就是说$真实的第k大 \ge 迭代x次的第k大$,既然每一次迭代会变小,那么迭代1次总可以得到最大可能的第k大就是真实的第k大;然后就是不停地取出当前的最大值,去更新,如果这个节点更新的次数超过$n-1$次,那么就不能再更新了,因为它最多和$n-1$个数组合,即最多拥有$n-1$个异或值。

那如何用Trie求某个数的第k大的异或值呢,用主席树的思想,看当前节点的反方向子节点下的节点数是否大于等于k,如果大于等于k则可以往反方向走,否则只能正着走并用k减去节点个数

可以参照这个图理解:

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 100010;
struct edge
{
    int to, nxt;
    LL v;
    edge() {}
    edge(int _to, int _nxt, LL _v): to(_to), nxt(_nxt), v(_v) {}
} E[N << 1];
struct Trie
{
    int nxt[2];
    int cnt;
    LL v;
    void init()
    {
        nxt[0] = nxt[1] = 0;
        cnt = 0;
        v = 0;
    }
} L[N * 61];
struct info
{
    int k;
    LL val;
    LL Max_xor_val;
    bool operator<(const info &rhs)const
    {
        return Max_xor_val < rhs.Max_xor_val;
    }
};
int head[N], tot;
LL arr[N];
int sz;
int n, m;
priority_queue<info>Q;
pii query[N << 1];
LL ans[N << 1];

void init()
{
    CLR(head, -1);
    tot = 0;
    sz = 1;
    L[0].init();
    while (Q.size())
        Q.pop();
}
inline void add(int s, int t, LL d)
{
    E[tot] = edge(t, head[s], d);
    head[s] = tot++;
}
void dfs(int u, int f, LL sum)
{
    arr[u] = sum;
    for (int i = head[u]; ~i; i = E[i].nxt)
    {
        int v = E[i].to;
        if (v != f)
            dfs(v, u, sum ^ E[i].v);
    }
}
void Insert(LL val)
{
    int u = 0;
    for (int i = 60; i >= 0; --i)
    {
        int v = (val >> i) & 1;
        if (!L[u].nxt[v])
        {
            L[sz].init();
            L[u].nxt[v] = sz++;
        }
        u = L[u].nxt[v];
        ++L[u].cnt;
    }
    L[u].v = val;
}
LL getKth(LL val, int k)
{
    if (k > n - 1)
        return -1;
    int u = 0;
    for (int i = 60; i >= 0; --i)
    {
        int v = (val >> i) & 1;
        int cnt = L[L[u].nxt[v ^ 1]].cnt;
        if (cnt >= k)
            u = L[u].nxt[v ^ 1];
        else
        {
            k -= cnt;
            u = L[u].nxt[v];
        }
    }
    return val ^ L[u].v;
}
int main(void)
{
    int u, v, i;
    LL x;
    while (~scanf("%d", &n) && n)
    {
        init();
        for (i = 1; i < n; ++i)
        {
            scanf("%d%d%I64d", &u, &v, &x);
            add(u, v, x);
            add(v, u, x);
        }
        scanf("%d", &m);
        for (i = 0; i < m; ++i)
        {
            scanf("%d", &query[i].first);
            query[i].second = i;
        }
        sort(query, query + m);

        dfs(1, -1, 0LL);
        for (i = 1; i <= n; ++i)
            Insert(arr[i]);
        for (i = 1; i <= n; ++i)
        {
            LL Max_xor_val = getKth(arr[i], 1);
            if (~Max_xor_val)
                Q.push({1, arr[i], Max_xor_val});
        }
        int Rank = 1;
        for (i = 0; i < m; ++i)
        {
            while (!Q.empty() && Rank < query[i].first)//每次取最大的节点进行扩展
            {
                info now = Q.top();
                Q.pop();
                ++now.k;
                LL Max_xor_val = getKth(now.val, now.k);
                if (~Max_xor_val)
                {
                    now.Max_xor_val = Max_xor_val;
                    Q.push(now);
                }
                ++Rank;
            }
            if (!Q.empty())
                ans[query[i].second] = Q.top().Max_xor_val;
            else
                ans[query[i].second] = -1;
        }
        for (i = 0; i < m; ++i)
            printf("%I64d\n", ans[i]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/Blackops/p/7519271.html

weixin151云匹面粉直供微信小程序+springboot后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值