题意:给出一个n个点的树,从某一点到另一个不同点的值是路径上的边权异或和,求第k大的值。
思路:开始想树分治想了半天没什么思路。后来看了看题解,发现这题思路还是很好的。首先随便选一个根节点,dfs一下算出根到每个点的异或和,某两点的值其实就等于这两个点到根节点的异或和。将所有点插入trie树,那么就可以通过trie找出这个点到其他点异或和第k大的,方法大概是这样,假设当前trie中的结点为u,那么下一步走使得异或值为1的那一个分支是比较大的,那么算出走这一步最多有多少个结点,如果这些点总数>=k,那么就顺着它走,否则k减去节点数,从另一个分支走,这样就能找到第k大的了。然后我们就可以对于每个结点,维护一个当前的最大值,把它们放到优先队列中去,每次挑最大的,然后找出第k+1大的添加到优先队列中,这样就可以找出前k大的了。。。
另外,不知道是我读题没读对还是数据有问题,有个地方有问题啊
以第一组数据来说,前6大的分别应该是
(2 3) : 3
(3 2) : 3
(1 2) : 2
(2 1) : 2
(1 3) : 1
(3 1) : 1
但是最后一组不算答案才正确,也就是说查询第6大的要输出-1,不明白为什么这样才能AC。
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-6
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
const int Msize=61;
int ch[maxn*Msize][2],size[maxn*Msize],tot;
ll val[maxn*Msize],p[Msize];
void Init()
{
ch[0][0]=ch[0][1]=0;
tot=size[0]=0;
val[0]=-1;
}
void Insert(ll x)
{
int u=0;
for(int i=Msize-1;i>=0;--i)
{
int c=(x&p[i])>0;
if(!ch[u][c])
{
ch[u][c]=++tot;
ch[tot][0]=ch[tot][1]=0;
size[tot]=0;val[tot]=-1;
}
u=ch[u][c];
size[u]++;
}
val[u]=x;
}
struct Edge
{
int v;
ll w;
int next;
Edge(int v=0,ll w=0,int next=0):v(v),w(w),next(next){}
}edges[maxn<<1];
struct Query
{
int id,k;
bool operator <(const Query &a) const
{
return k<a.k;
}
}querys[maxn];
int head[maxn],nEdge,n,m;
ll xv[maxn],ans[maxn];
void AddEdges(int u,int v,ll w)
{
edges[++nEdge]=Edge(v,w,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,w,head[v]);
head[v]=nEdge;
}
void dfs(int u,int fa,ll now)
{
xv[u]=now;
Insert(now);
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(v==fa) continue;
dfs(v,u,now^edges[k].w);
}
}
struct Node
{
int k;
ll num,mxv;
bool operator <(const Node &a) const
{
return mxv<a.mxv;
}
bool next()
{
k++;
if(k>=n) return false;
int kk=k,u=0;
for(int dep=Msize-1;dep>=0;--dep)
{
int c=((num&p[dep])>0)^1;
int v=ch[u][c];
if(v&&size[v]>=kk) u=ch[u][c];
else if(v&&size[v]<kk)
{
kk-=size[v];
u=ch[u][c^1];
}
else u=ch[u][c^1];
}
mxv=val[u]^num;
return true;
}
};
void solve()
{
sort(querys,querys+m);
priority_queue<Node>q;
Node node;
for(int i=1;i<=n;++i)
{
node.k=0;
node.num=xv[i];
if(node.next()) q.push(node);
}
memset(ans,0xff,sizeof(ans));
int rank=0;
ll tmp;
for(int i=0;i<m;++i)
{
while(!q.empty()&&rank<querys[i].k)
{
rank++;
node=q.top();q.pop();
tmp=node.mxv;
if(node.next()) q.push(node);
}
if(querys[i].k==rank&&querys[i].k!=(ll)n*(n-1))
ans[querys[i].id]=tmp;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
p[0]=1;
for(int i=1;i<Msize;++i) p[i]=p[i-1]<<1;
while(~scanf("%d",&n))
{
if(n==0) break;
memset(head,0xff,sizeof(head));
nEdge=-1;
Init();
int u,v;
ll w;
for(int i=1;i<n;++i)
{
scanf("%d%d%I64d",&u,&v,&w);
AddEdges(u,v,w);
}
dfs(1,-1,0);
scanf("%d",&m);
for(int i=0;i<m;++i)
{
scanf("%d",&querys[i].k);
querys[i].id=i;
}
solve();
for(int i=0;i<m;++i)
printf("%I64d\n",ans[i]);
}
return 0;
}