• CF840E In a Trap


    一、题目

    点此看题

    二、解法

    感冒在家两天,今天才回学校,虽然博客鸽了一天但是我换签名了

    对于询问其实可以分块,每一块的前 \(8\) 位都是一样的,那么处理后 \(8\) 位就可以了,设 \(f(u,i)\) 表示 \(u\) 向上的 \(256\) 个节点中,最大的 \(a_v\oplus (dep_u-dep_v)\oplus (i\cdot 256)\),那么查询可以先跳整块再跳散块。

    对于上面这东西显然可以值域分治,对于前 \(8\) 位我们可以搞一个 \(\tt trie\) 树直接查询。对于后 \(8\) 位我们开一个桶 \(g(u,i)\) 表示前 \(8\) 位为 \(i\)\(a_v\),最大的 \(((dep_u-dep_v)\oplus a_v)\and 256\),那么 \(f(u,i)\) 就可以通过这两者拼凑出来。

    预处理的复杂度是 \(O(n\log n\sqrt n)\),询问的复杂度是 \(O(q\sqrt n)\)

    三、总结

    看到 \(a_i\leq n\) 之类的限制多半要用到值域分块,对于加法和异或的混合问题可以考虑对半拆位。

    #include <cstdio>
    #include <vector>
    #include <iostream>
    using namespace std;
    const int M = 50005;
    const int N = 256;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,a[M],fa[M],dep[M],f[M][260],mx[M][260];
    vector<int> g[M];int cnt,ch[M][2],lst[M];
    void upd(int &x,int y) {x=max(x,y);}
    void ins(int x)
    {
    	for(int i=7,p=1;i>=0;i--)
    	{
    		int w=(x>>i)&1;
    		if(!ch[p][w]) ch[p][w]=++cnt;
    		p=ch[p][w];
    	}
    }
    int ask(int x,int u)
    {
    	int v=0,res=0;
    	for(int i=7,p=1;i>=0;i--)
    	{
    		int w=((x>>i)&1)^1;
    		if(ch[p][w]) p=ch[p][w],res|=(1<<i);
    		else p=ch[p][w^=1];
    		v|=(w<<i);
    	}
    	return (res<<8)|mx[u][v];
    }
    void dfs(int u)
    {
    	if(dep[u]>=N)
    	{
    		for(int i=1;i<=cnt;i++) ch[i][0]=ch[i][1]=0;
    		cnt=1;int i=u;
    		for(;dep[u]-dep[i]<N;i=fa[i])
    		{
    			upd(mx[u][a[i]>>8],(dep[u]-dep[i]^a[i])&255);
    			ins(a[i]>>8);
    		}
    		lst[u]=i;
    		for(i=0;i<N;i++) f[u][i]=ask(i,u);
    	}
    	for(auto v:g[u]) if(v^fa[u])
    		fa[v]=u,dep[v]=dep[u]+1,dfs(v);
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		g[u].push_back(v);
    		g[v].push_back(u);
    	}
    	dep[1]=1;dfs(1);
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read(),ans=0,d=0;
    		for(;dep[v]-dep[u]>=N;v=lst[v],d++) ans=max(ans,f[v][d]);
    		for(d<<=8;v!=fa[u];v=fa[v],d++) ans=max(ans,d^a[v]);
    		printf("%d\n",ans);
    	}
    }
    
  • 相关阅读:
    Android应用开发之避免内存泄露
    史上最经典的数据库面试题之二
    某大型银行深化系统之二十一:Log4j执行性能
    ruby支持批量数组的定义
    为VIM提供python代码提示功能
    使用win7登陆远程机器时自动保存密码
    安装Beanstalk
    在linux下安装或者卸载nginx
    python的数据类型
    使Ruby自动定位查找本地路径
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15787730.html
Copyright © 2020-2023  润新知