SCOI2016幸运数字(树剖/倍增/点分治+线性基)

题目链接

loj
luogu

题意

求树上路径最大点权异或和

自然想到(维护树上路径)+ (维护最大异或和)
那么有三种方法可以选择
1.树剖+线性基
2.倍增+线性基
3.点分治+线性基

至于线性基的合并
一共就是long级的
暴力合并就好啦

这是一份在loj T掉在洛谷AC的可怜代码

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector> 
using namespace std;
const int N = 2e4 + 2;
const int LIM = 60;

inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

struct Edge{
    int v, next;
}edge[N << 1];
int esize, head[N];
inline void addedge(int x, int y){
    edge[++esize] = (Edge){y, head[x]};
    head[x] = esize;
}

struct XXJ{
    long long w[LIM + 2];
    XXJ(){
        memset(w, 0, sizeof(w));
    }
    void ins(long long x){
        for(int i = LIM; ~i; --i){
            if(!(x >> i)) continue;
            else if(!w[i]){w[i] = x; break;}
            x ^= w[i];
        }
    }
    void print(){
        long long res = 0;
        for(int i = LIM; ~i; --i) 
            if((res ^ w[i]) > res) res ^= w[i];
 		printf("%lld\n", res);
    }
}px[N][18];
long long w[N];
int p[N][18], dep[N];
int n, m;

XXJ merge(XXJ x, XXJ y){
    for(int i = LIM; i >= 0; --i){
        if(y.w[i]) x.ins(y.w[i]);
    }
    return x;
}

XXJ LCA(int x, int y){
    XXJ res;
    res.ins(w[x]); res.ins(w[y]);
    if(dep[x] < dep[y]) swap(x, y); 
    for(int i = 15; i >= 0; --i)
        if(dep[x] - (1 << i) >= dep[y]){
        	res = merge(res, px[x][i]);
        	x = p[x][i];
        }
    if(x == y) return res;
    for(int i = 15; i >= 0; --i){
    	if(p[x][i] != p[y][i]){
    		res = merge(res, px[x][i]);
    		res = merge(res, px[y][i]);
    		x = p[x][i], y = p[y][i];
    	}
    }
    res = merge(res, px[x][0]);
    return res;
}

void dfs(int x, int ff){
    dep[x] = dep[ff] + 1;
    p[x][0] = ff;
    px[x][0].ins(w[ff]); 
    for(int i = head[x], vv; ~i; i = edge[i].next){
        vv = edge[i].v; if(vv == ff) continue;
        dfs(vv, x);
    }
}

void calc(){
    for(int i = 1; i <= 15; ++i){
        for(int j = 1; j <= n; ++j){
            p[j][i] = p[p[j][i - 1]][i - 1];
            px[j][i] = merge(px[j][i - 1], px[p[j][i - 1]][i - 1]);
        }
    }
}
 
int main() {
    memset(head, -1, sizeof(head));
    
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i){
        scanf("%lld", &w[i]);
    } 
    for(int i = 1, x, y; i < n; ++i){
        scanf("%d%d", &x, &y);
        addedge(x, y); addedge(y, x);
    }
    dfs(1, 0); 
    calc();
    for(int i = 1, x, y; i <= m; ++i){
        x = read(), y = read();
        XXJ res = LCA(x, y);
        res.print();
    }
    return 0;
}  
posted @ 2019-02-25 20:27  hjmmm  阅读(191)  评论(0编辑  收藏  举报