Ants
题目叙述
给一棵边权树,一直蚂蚁从一个节点爬到另一个节点获得的分数是路径上的所有边异或和。m 个询问,求第k大。
解法
首先求出根节点到所有节点的异或和,那么节点-> 节点的异或和就是 两个根到节点的异或和 的 异或和。
将所有的节点插入 Trie 树中,然后对于 n 个节点维护一个优先队列——就是这 n 个节点在Trie 树中的位置和当前的异或值。
还是把询问离线从小到大依次从优先队列中弹数
1、如果正好是第 询问 个那么记录。否则忽略
2、将当前弹出节点的位置移到下一个。这部分就有两种解法。
Solution Of BNU lsy
李思源 18:53:04
就是你在某个节点的时候
李思源 18:53:22
然后比方说发现当前位选1比较大
李思源 18:53:42
然后回溯前选的就是1
李思源 18:53:51
并且这个位置可以选0
李思源 18:53:58
就往0那边走
李思源 18:54:01
否则回溯
因为太弱了没想清楚所以没写出来。。。BNU居然搞出来了太神了。。
Solution Of Dshawn by cxlove
她是爱酱,喵~ http://blog.csdn.net/ACM_cxlove?viewmode=contents
记录当前节点已经是rank第几大了,下一步就是要求 rank 的下一个。这个只要用 Trie 树记录一下自己有多少个孩子就能 log(1e18) 的时间复杂度内求出来。即——
假设当前位置的二进制是 0 ,那么最大的肯定是 走 1 那条边。
1、如果 1 的子树中节点个数 >= rank ,那么走下去
2、如果小于 rank ,那么 rank -= 节点个数,走 0;
3、如果没有 1 的子树,那么走 0;
如果是 0 则同理。
code
const int N = 1e5 + 9;
const int M = 61;
LL mm[M];
struct Node{
int son[2];
int size;
LL val;
void init(){
FLC(son , -1);
size = 0;
val = -1;
}
}node[N * M + 1];
int L , root;
int newNode(){
node[L].init();
return L++;
}
void insertTrie(LL x){
int now = root;
node[root].size++;
for (int i = M - 1 ; i >= 0 ; --i){
int r = (x & mm[i]) > 0;
if (node[now].son[r] == -1)
node[now].son[r] = newNode();
now = node[now].son[r];
node[now].size++;
}
node[now].val = x;
}
int head[N];
struct Edge{
int v ; int next;
LL len;
}edge[N << 1];
LL value[N];
int tot;
void addedge(int x , int y , LL z){
edge[tot].next = head[x];
edge[tot].v = y;
edge[tot].len = z;
head[x] = tot++;
}
int n , m;
struct Query{
int k;
int id;
bool operator < (const Query & A) const{
return k < A.k;
}
}q[N];
LL ans[N];
struct Pointer{
int k;
LL val;
LL id;
bool operator < (const Pointer & A) const{
return val < A.val;
}
bool movenext(){
k++;
if (k >= n) return false;
int kk = k;
int now = root;
int dep = 60;
while(node[now].val == -1){
int f = ((id & mm[dep]) != 0) ^ 1;
dep--;
if (node[now].son[f] != -1 && node[node[now].son[f]].size >= kk)
now = node[now].son[f];
else if (node[now].son[f] != -1 && node[node[now].son[f]].size < kk){
kk -= node[node[now].son[f]].size;
now = node[now].son[1 - f];
}
else now = node[now].son[1 - f];
}
val = id ^ node[now].val;
// cout << k << "th value for " << id << " is " << val <<endl;
return true;
}
};
priority_queue<Pointer> Q;
int Cnter;
void dfs(int u , int v , LL now){
insertTrie(now);
value[Cnter++] = now;
for (int i = head[u] ; i != -1 ; i = edge[i].next){
int to = edge[i].v ; LL len = edge[i].len;
if (to == v) continue;
dfs(to , u , now ^ len);
}
}
void solve(){
FLC(head , -1); tot = 0;
for (int i = 0 ; i < n - 1 ; ++i){
int x , y ; LL z;
RD(x , y);RD(z);
addedge(x , y , z);
addedge(y , x , z);
}
L = 0;
root = newNode();
Cnter = 0;
dfs(1 , -1 , 0);
RD(m);
for (int i = 0 ; i < m ; ++i){
scanf("%d" , &q[i].k);
q[i].id = i;
}
sort(q , q + m);
while(!Q.empty()) Q.pop();
for (int i = 0 ; i < n ; ++i){
Pointer now;
now.k = 0;
now.id = value[i];
if(now.movenext()) Q.push(now);
}
int rank = 0;
for (int i = 0 ; i < m ; ++i){
LL ret = 0;
while(!Q.empty() && rank < q[i].k){
rank++;
Pointer p = Q.top();
Q.pop();
ret = p.val;
if (p.movenext()) Q.push(p);
}
if (Q.empty()) ans[q[i].id] = -1;
else ans[q[i].id] = ret;
}
for (int i = 0 ; i < m ; ++i)
printf("%I64d\n" , ans[i]);
}
int main(){
for (int i = 0 ; i < M ; ++i) mm[i] = 1ll << i;
while(RD(n)) solve();
}