zoukankan      html  css  js  c++  java
  • 题解 P3292 【[SCOI2016]幸运数字】

    题目链接

    Solution [SCOI2016]幸运数字

    题目大意:给定一棵树,每次询问一条路径上的点权的异或最大值

    线性基,倍增


    分析:

    看到一个集合,要求一个子集使得异或值最大我们基本上就可以往线性基上想了

    首先线性基的合并复杂度是(O(logm^2))的,(m)为值域

    于是sbzcy写了个树剖TLE一片

    我们需要考虑优化,由于不带修改,是静态询问,我们考虑用类似求(LCA)的方法,倍增来合并一条路径上的线性基

    注意一下边界问题的处理,以及轻微卡常,请使用读入优化

    #include <cstdio>
    #include <cctype>
    #include <vector>
    using namespace std;
    typedef long long ll;
    const int maxn = 32769,limit = 62,maxdep = 23;
    inline ll read(){
    	ll x = 0;char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x;
    }
    struct LB{//线性基
    	ll p[limit + 1];
    	inline ll query()const{
    		ll res = 0;
    		for(int i = limit;i >= 0;i--)
    			if((res ^ p[i]) > res)res ^= p[i];
    		return res;
    	}
    	inline void insert(ll x){
    		for(int i = limit;i >= 0;i--){
    			if(!(x >> i))continue;
    			if(!p[i]){
    				p[i] = x;
    				break;
    			}
    			x ^= p[i];
    		}
    	}
    	inline void merge(const LB &x){
    		for(int i = limit;i >= 0;i--)
    			if(x.p[i])insert(x.p[i]);
    	}
    }f[maxn][maxdep + 1],zero;
    vector<int> G[maxn];
    inline void addedge(int from,int to){
    	G[from].push_back(to);
    }
    int n,q,faz[maxn][maxdep + 1],dep[maxn];
    ll val[maxn];
    void dfs(int u){//预处理倍增
    	dep[1] = 1;
    	f[u][0].insert(val[u]);
    	for(int i = 1;i <= maxdep;i++)
    		f[u][i] = f[u][i - 1],f[u][i].merge(f[faz[u][i - 1]][i - 1]),faz[u][i] = faz[faz[u][i - 1]][i - 1];
    	for(int v : G[u]){
    		if(v == faz[u][0])continue;
    		faz[v][0] = u;
    		dep[v] = dep[u] + 1;
    		dfs(v);
    	}
    }
    inline ll path_query(int x,int y){//查询
    	LB res = zero;
    	if(dep[x] < dep[y])swap(x,y);
    	for(int i = maxdep;i >= 0;i--)
    		if(dep[faz[x][i]] >= dep[y])
    			res.merge(f[x][i]),x = faz[x][i];
    	if(x == y)return res.merge(f[x][0]),res.query();
    	for(int i = maxdep;i >= 0;i--)
    		if(faz[x][i] != faz[y][i]){
    			res.merge(f[x][i]),x = faz[x][i];
    			res.merge(f[y][i]),y = faz[y][i];
    		}
    	res.merge(f[x][0]);
    	res.merge(f[y][0]);
    	res.merge(f[faz[x][0]][0]);
    	return res.query();
    }
    int main(){
    	n = read(),q = read();
    	for(int i = 1;i <= n;i++)val[i] = read();
    	for(int x,y,i = 1;i < n;i++)
    		x = read(),y = read(),addedge(x,y),addedge(y,x);
    	dfs(1);
    	for(int x,y,i = 1;i <= q;i++)
    		x = read(),y = read(),printf("%lld
    ",path_query(x,y));
    	return 0;
    }
    
  • 相关阅读:
    TCP源码—连接建立
    TCP系列02—连接管理—1、三次握手与四次挥手
    TCP系列01—概述及协议头格式
    ubuntu软件管理apt与dpkg
    318. Maximum Product of Word Lengths
    317. Shortest Distance from All Buildings
    316. Remove Duplicate Letters
    315. Count of Smaller Numbers After Self
    314. Binary Tree Vertical Order Traversal
    313. Super Ugly Number
  • 原文地址:https://www.cnblogs.com/colazcy/p/11515173.html
Copyright © 2011-2022 走看看