zoukankan      html  css  js  c++  java
  • BZOJ 4568 [Scoi2016]幸运数字(树链剖分 + 异或线性基)

    题目链接  BZOJ 4568

    考虑树链剖分+线段树维护每一段区域的异或线性基

    对于每个询问,求出该点集的异或线性基。然后求一下这个线性基里面能异或出的最大值即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define ls		i << 1
    #define	rs		i << 1 | 1
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    
    
    typedef long long LL;
    
    const int N = 2e4 + 10;
    
    struct lb{
    	LL d[70];
    	int cnt;
    	void clear(){
    		memset(d, 0, sizeof d);
    		cnt = 0;
    	}
    	bool ins(LL val){
    		dec(i, 62, 0) if (val & (1LL << i)){
    			if (!d[i]){ d[i] = val; break; }
    			val ^= d[i];
    		}
    		return val > 0;
    	}
    	LL qmax(){
    		LL ret = 0;
    		dec(i, 62, 0) if ((ret ^ d[i]) > ret) ret ^= d[i];
    		return ret;
    	}
    	LL qmin(){
    		rep(i, 0, 62) if (d[i]) return d[i];
    		return 0;
    	}
    };
    
    lb t[N << 3];
    
    int f[N], fp[N], son[N], deep[N], father[N], sz[N], top[N];
    int q, tot, n;
    LL a[N];
    vector <int> v[N];
    
    lb merge(const lb &n1, const lb &n2){
    	lb ret = n1;
    	dec(i, 60, 0) if (n2.d[i]) ret.ins(n2.d[i]);
    	return ret;
    }
    
    void dfs1(int x, int fa, int dep){
    	deep[x] = dep;
    	father[x] = fa;
    	son[x] = 0;
    	sz[x] = 1;
    	int ct = (int)v[x].size();
    	rep(i, 0, ct - 1){
    		int u = v[x][i];
    		if (u == fa) continue;
    		dfs1(u, x, dep + 1);
    		sz[x] += sz[u];
    		if (sz[son[x]] < sz[u]) son[x] = u;
    	}
    }
    
    void dfs2(int x, int tp){
    	top[x] = tp;
    	f[x] = ++tot;
    	fp[f[x]] = x;
    	if (son[x]) dfs2(son[x], tp);
    	int ct = (int)v[x].size();
    	rep(i, 0, ct - 1){
    		int u = v[x][i];
    		if (u == father[x] || u == son[x]) continue;
    		dfs2(u, u);
    	}
    }
    
    void build(int i, int L, int R){
    	if (L == R){
    		t[i].ins(a[fp[L]]);
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    	build(lson);
    	build(rson);
    	t[i] = merge(t[ls], t[rs]);
    }
    
    lb query(int i, int L, int R, int l, int r){
    	if (L == l && R == r) return t[i];
    	int mid = (L + R) >> 1;
    	if (r <= mid) return query(lson, l, r);
    	else if (l > mid) return query(rson, l, r);
    	else return merge(query(lson, l, mid), query(rson, mid + 1, r));
    }
    
    lb work(int x, int y){
    	lb ret;
    	ret.clear();
    	int f1 = top[x], f2 = top[y];
    	for (; f1 != f2; ){
    		if (deep[f1] < deep[f2]) swap(f1, f2), swap(x, y);
    		ret = merge(ret, query(1, 1, n, f[f1], f[x]));
    		x = father[f1], f1 = top[x];
    	}
    
    	if (x == y) return merge(ret, query(1, 1, n, f[x], f[y]));
    	if (deep[x] > deep[y]) swap(x, y);
    	return merge(ret, query(1, 1, n, f[x], f[y]));
    }
    
    
    int main(){
    
    	scanf("%d%d", &n, &q);
    	rep(i, 1, n) scanf("%lld", a + i);
    
    	rep(i, 2, n){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    
    	dfs1(1, 0, 0);
    	dfs2(1, 1);
    	build(1, 1, n);
    
    	while (q--){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		lb cnt = work(x, y);
    		printf("%lld
    ", cnt.qmax());
    	}
    
    
    	return 0;
    }
    

      

  • 相关阅读:
    python 3.x报错:No module named 'cookielib'或No module named 'urllib2'
    Xshell实现Windows和使用跳板机跳转的远程Linux互传文件
    Linux scp常用命令
    正则表达式
    [NBUT 1458 Teemo]区间第k大问题,划分树
    [hdu5416 CRB and Tree]树上路径异或和,dfs
    [vijos P1008 篝火晚会]置换
    [hdu5411 CRB and Puzzle]DP,矩阵快速幂
    [hdu4713 Permutation]DP
    [hdu4710 Balls Rearrangement]分段统计
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7774578.html
Copyright © 2011-2022 走看看