• 【CF840E】In a Trap 分块


    【CF840E】In a Trap

    题意:一棵n个点的树,第i个点权值为ai,q次询问,每次给定u,v(u是v的祖先),求对于所有在u-v上的点i,$a_i mathrm{xor} dis(i,v)$的最大值。

    $nle 50000,qle 150000,a_ile n$

    题解:考虑分块,每块大小为$2^8=256$,对于一个点v,我们从v往上走,每经过256个点便分为一块。即,对于一个块中的所有i,dis(i,v)的前8位是相同的,并且后8位是0...255,那么我们可以令块内每个i的权值变为{0...255} xor ai,此时我们只需要考虑询问的前8位就行了。那么我们令f[a][b]表示第a个块遇到一个前8位是b的询问时,答案的最大值是多少。我们可以将{0...255} xor ai扔到Trie树里,就能预处理出f数组了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=50010;
    const int B=256;
    int f[maxn][B+4],fa[maxn][B+4],dep[maxn],head[maxn],nxt[maxn<<1],to[maxn<<1],ch[maxn][2],mx[maxn],v[maxn];
    int n,m,tot,ans,cnt;
    inline void insert(int v)
    {
    	int i,x=1,d;
    	for(i=15;i>=8;i--)
    	{
    		d=(v>>i)&1;
    		if(!ch[x][d])	ch[x][d]=++tot,ch[tot][0]=ch[tot][1]=0,mx[tot]=0;
    		x=ch[x][d];
    	}
    	mx[x]=max(mx[x],v&255);
    }
    inline int query(int v)
    {
    	int i,x=1,ret=0,d;
    	for(i=7;i>=0;i--)
    	{
    		d=!((v>>i)&1);
    		if(!ch[x][d])	d^=1;
    		else	ret+=1<<(i+8);
    		x=ch[x][d];
    	}
    	ret+=mx[x];
    	return ret;
    }
    void dfs(int x)
    {
    	int i;
    	fa[x][0]=x;
    	for(i=2;i<=B;i++)	fa[x][i]=fa[fa[x][1]][i-1];
    	tot=1,ch[1][0]=ch[1][1]=0;
    	for(i=0;i<B;i++)	if(fa[x][i])	insert(v[fa[x][i]]^i);
    	for(i=0;i<B;i++)	f[x][i]=query(i);
    	for(i=head[x];i!=-1;i=nxt[i])	if(to[i]!=fa[x][1])	dep[to[i]]=dep[x]+1,fa[to[i]][1]=x,dfs(to[i]);
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,j,t,a,b;
    	for(i=1;i<=n;i++)	v[i]=rd();
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	dep[1]=1,dfs(1);
    	for(i=1;i<=m;i++)
    	{
    		b=rd(),a=rd(),t=0,ans=0;
    		while(dep[fa[a][B-1]]>=dep[b])	ans=max(ans,f[a][t]),t++,a=fa[a][B];
    		for(j=0;j<=dep[a]-dep[b];j++)	ans=max(ans,(t<<8|j)^v[fa[a][j]]);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }//5 3 0 3 2 1 4 1 2 2 3 3 4 3 5 1 4 1 5 2 4
  • 相关阅读:
    IP地址和进制转换
    Cisco交换机常见配置
    macOS上的autoreconf错误导致无法安装问题
    LG P5147 随机数生成器
    LG P1879 [USACO06NOV]Corn Fields G
    LG P5017 [NOIP2018]摆渡车
    mysql触发器trigger详解
    MybatisPuls中QueryWrapper的select、update的用法
    @Transactional各属性详解
    Linux如何查看进程、杀死进程、启动进程等常用命令(包括常用的命令,如查看文件,修改文件读写权限、寻找文件等)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8283319.html
Copyright © 2020-2023  润新知