• HDU4776 Ants(Trie && xor)


    之前mark下来的一道题,今天填一下坑。

    题意是这样子的。给你一棵边上有权的树。然后有树上两点(u,v)的路径有n*(n-1)条,路径(u,v)的权值是边权的xor. 然后下面有m个询问,询问你n*(n-1)条路径中的第k大是多少。(k<=200000)

    首先树路径的xor是一个很经典的问题,首先求出所有点i到根路径的xor值val[i]。然后我们就可以发现val[u]^val[v]就是u,v路径的xor值。

    然后第二个很经典的地方就是最大xor.给你一个数组,要你求数组里面xor最大的一对数。方法是根据二进制的最高位到最低位插到一棵Trie树上,然后每次询问和x xor起来最大的,就从最高位贪心地去匹配,譬如最高位是1我们就可以去匹配0。

    本题的突破口在于k<=200000, 因为k小,所以我们完全可以把所有的k求出来,把询问离线一下就好了。

    现在关键是我们怎么能够顺次得到第k大的呢? 方法其实很简单,首先我们对每个权值在Trie树上求出和它最大的那个,压入一个优先队列里面。然后很显然第一大的必然是优先队列的队首,然后优先队列队首的元素弹出来,这个元素里需要保存的是它是第i个结点的第k大,然后我们再把第i个结点的k+1大压入(当k达到n-1就不压了)。然后问题转化为对于一个数x,求它能匹配到的第k大,做法也很简单,Trie树上存向0走和向1走的点的个数各有多少个,如果匹配到1的时候的结点树>=k,就往匹配到1的方向走,否则就往0走,然后对应的k减去相应的值。

    坑的话有两个吧,一是注意ll,二是当n=1的时候优先队列不用初始化,因为这样会把n=1当成有解的。

    #pragma warning(disable:4996)
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <cstdio>
    using namespace std;
    
    #define ll long long
    #define maxn 150000
    #define MAXCHAR 61
    
    struct Edge
    {
    	int v; ll w;
    	Edge(int _v, ll _w) :v(_v), w(_w){}
    	Edge(){}
    };
    
    vector<Edge> G[maxn];
    ll val[maxn];
    int n, m;
    
    void dfs(int u, int fa,ll vv)
    {
    	val[u] = vv;
    	for (int i = 0; i < G[u].size(); i++){
    		int v = G[u][i].v;
    		ll w = G[u][i].w;
    		if (v == fa) continue;
    		dfs(v, u, vv^w);
    	}
    }
    
    struct Trie
    {
    	Trie *go[2];
    	int num[2];
    	void init(){
    		memset(go, 0, sizeof(go));
    		memset(num, 0, sizeof(num));
    	}
    }*root,pool[maxn*65];
    int tot;
    
    void insert(ll x)
    {
    	Trie *p = root;
    	for (int i = MAXCHAR; i >= 0; i--){
    		int ind = (x >> i) & 1;
    		p->num[ind]++;
    		if (p->go[ind] != NULL) {
    			p = p->go[ind];
    		}
    		else{
    			pool[tot].init();
    			p->go[ind] = &pool[tot++];
    			p = p->go[ind];
    		}
    	}
    }
    
    ll get(ll x, int k)
    {
    	Trie *p = root; int kk = k; ll ret = 0;
    	for (int i = MAXCHAR; i >= 0; i--){
    		int ind = (x >> i) & 1;
    		if (p->num[ind ^ 1] >= kk){
    			ret += (1LL << i);
    			p = p->go[ind ^ 1];
    		}
    		else{
    			kk -= p->num[ind ^ 1];
    			p = p->go[ind];
    		}
    	}
    	return ret;
    }
    
    struct Query
    {
    	int k, id;
    	bool operator < (const Query &b) const{
    		return k < b.k;
    	}
    }q[maxn];
    
    struct Node
    {
    	int t, k;
    	ll val;
    	Node(int _t, int _k, ll _val) :t(_t), k(_k), val(_val){}
    	Node(){}
    	bool operator < (const Node &b) const{
    		return val < b.val;
    	}
    };
    
    ll ans[maxn];
    priority_queue<Node> que;
    
    int main()
    {
    	while (cin >> n && n)
    	{
    		int ui, vi; ll wi;
    		for (int i = 0; i <= n; i++) G[i].clear();
    		for (int i = 0; i < n-1; i++){
    			scanf("%d%d%I64d", &ui, &vi, &wi);
    			G[ui].push_back(Edge(vi, wi));
    			G[vi].push_back(Edge(ui, wi));
    		}
    		dfs(1, -1, 0);
    		tot = 0; root = &pool[tot++]; root->init();
    		for (int i = 1; i <= n; i++){
    			insert(val[i]);
    		}
    		scanf("%d", &m);
    		for (int i = 0; i < m; i++){
    			scanf("%d", &q[i].k);
    			q[i].id = i;
    		}
    		sort(q, q + m);
    		while (!que.empty()) que.pop();
    		for (int i = 1; i <= n&&n!=1; i++){
    			que.push(Node(i, 1, get(val[i], 1)));
    		}
    		int cur = 0; int idx = 1;
    		while (!que.empty() && cur < m){
    			Node node = que.top(); que.pop();
    			if (idx== q[cur].k){
    				ans[q[cur].id] = node.val;
    				cur++; idx++;
    			}
    			else{
    				idx++;
    			}
    			if (node.k < n-1){
    				que.push(Node(node.t, node.k + 1, get(val[node.t], node.k + 1)));
    			}
    		}
    		for (int i = cur; i < m; i++){
    			ans[q[i].id] = -1;
    		}
    		for (int i = 0; i < m; i++){
    			printf("%I64d
    ", ans[i]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    企业微信通讯录替换-JqueryWEUI Picker替换通讯录
    页面window.onload冲突
    企业微信调试工具
    企业微信:错误码:50001 redirect_url 一例问题解决办法
    企业微信通讯录替换-Echarts中使用部门名称
    紫光拼音输入法切换中英文
    企业微信服务商平台申请
    企业微信通讯录替换-根据员工姓名查找工号
    微信开发 40001 invalid credential
    请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止
  • 原文地址:https://www.cnblogs.com/chanme/p/3703448.html
Copyright © 2020-2023  润新知