zoukankan      html  css  js  c++  java
  • luogu3292 [SCOI2016]幸运数字

    link

    题目大意:给一棵树,每个点有个权值,N<=2万

    20万次询问,每次询问查询某两个点路径上所有点的权值xjb异或的最大值

    首先看到xjb异或就可以断定是线性基了

    并且由于这是树上问题我们可以通过树剖Dfs序之类的手段搞成序列问题

    但是树剖+线段树的复杂度是 (O(log ^2Nlog^2 2^{60})) 的很明显会T

    由于本题不需要修改,可以考虑维护一个倍增,bij代表点i向上跳2的j次方这段路上所有点权值的一个线性基

    然后查询就是 (O(log Nlog^2 2^{60})) 的了,开O2勉强可过

    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    int n, q;
    long long init[20010];
    vector<int> out[20010];
    int fa[20010][16], depth[20010];
    
    struct linear_basis
    {
    	long long sb[61];
    	
    	linear_basis() { memset(this, 0, sizeof(linear_basis)); }
    	
    	void insert(long long x)
    	{
    		for (int i = 60; i >= 0; i--) if (x & (1LL << i))
    		{
    			if (sb[i] == 0) { sb[i] = x; return; }
    			else x ^= sb[i];
    		}
    	}
    	
    	long long query()
    	{
    		long long ans = 0;
    		for (int i = 60; i >= 0; i--)
    		{
    			if ((ans ^ sb[i]) > ans) ans ^= sb[i];
    		}
    		return ans;
    	}
    } b[20010][16];
    
    linear_basis operator+(const linear_basis &a, const linear_basis &b)
    {
    	linear_basis ans;
    	for (int i = 60; i >= 0; i--) if (a.sb[i]) ans.insert(a.sb[i]);
    	for (int i = 60; i >= 0; i--) if (b.sb[i]) ans.insert(b.sb[i]);
    	return ans;
    }
    
    void dfs(int x) { for (int i : out[x]) if (fa[x][0] != i) fa[i][0] = x, depth[i] = depth[x] + 1, dfs(i); }
    
    linear_basis qlca(int x, int y)
    {
    	if (depth[x] < depth[y]) swap(x, y);
    	linear_basis ans;
    	int sb = depth[x] - depth[y];
    	for (int i = 15; i >= 0; i--) if (sb & (1 << i)) ans = ans + b[x][i], x = fa[x][i];
    	if (x == y) { ans.insert(init[x]); return ans; }
    	for (int i = 15; i >= 0; i--) if (fa[x][i] != fa[y][i]) ans = ans + b[x][i] + b[y][i], x = fa[x][i], y = fa[y][i];
    	ans.insert(init[fa[x][0]]);
    	ans.insert(init[x]);
    	ans.insert(init[y]);
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &q);
    	for (int i = 1; i <= n; i++) scanf("%lld", &init[i]);
    	for (int x, y, i = 1; i < n; i++) scanf("%d%d", &x, &y), out[x].push_back(y), out[y].push_back(x);
    	dfs(1);
    	for (int i = 1; i <= n; i++) b[i][0].insert(init[i]);
    	for (int j = 1; j <= 15; j++) for (int i = 1; i <= n; i++)
    	{
    		fa[i][j] = fa[fa[i][j - 1]][j - 1];
    		b[i][j] = b[i][j - 1] + b[fa[i][j - 1]][j - 1];
    	}
    	for (int x, y, i = 1; i <= q; i++)
    	{
    		scanf("%d%d", &x, &y);
    		linear_basis fuck = qlca(x, y);
    		printf("%lld
    ", fuck.query());
    	}
    	return 0;
    }
    

    另外观察到本题可以离线,于是我们可以考虑淀粉质?

    淀粉质,每次淀粉质维护当前树上每个点到当前的根的线性基(每次只需要往他父亲的线性基里插入一个数然后粘过来,复杂度是log的),然后查询只需要合并两个线性基,复杂度比在线lca少一个log N。

    不太好写所以没写

  • 相关阅读:
    每天学一点MATLAB函数——文件编程函数
    每天学一点MATLAB函数——软件操作函数(1)
    C# 杂记
    ActiveX控件注册与反注册
    First Java Graphic Program
    判断式
    两个仿函数示例
    STL文件的读取与显示
    SQLite数据库(一)
    机器学习--如何理解Accuracy, Precision, Recall, F1 score
  • 原文地址:https://www.cnblogs.com/oier/p/10741174.html
Copyright © 2011-2022 走看看