zoukankan      html  css  js  c++  java
  • 可持久化01Trie树+LCA【p4592】[TJOI2018]异或

    Description

    现在有一颗以(1)为根节点的由(n)个节点组成的树,树上每个节点上都有一个权值(v_i)。现在有(Q)次操作,操作如下:

    • 1(;x;y):查询节点(x)的子树中与(y)异或结果的最大值
    • 2(;x;y;z):查询路径(x)(y)上点与(z)异或结果最大值

    Input

    第一行是两个数字(n,Q);

    第二行是(n)个数字用空格隔开,第(i)个数字(v_i)表示点(i)上的权值

    接下来(n-1)行,每行两个数,(x,y),表示节点(x)(y)之间有边

    接下来(Q)行,每一行为一个查询,格式如上所述.

    Output

    对于每一个查询,输出一行,表示满足条件的最大值。

    表示不太会可持久化(01Trie)

    参考着题解码了出来,还是有点不懂.

    但是又感觉懂得差不多。

    这个题差不多可以自己码出来,很好的一个题。

    可持久化(01Trie)思想还行,类似于主席树思想.

    用到了(lastroot).

    对于现在的自己,不太想深究具体构造,感觉网上讲解的这个不是很好。

    打算活过(NOIP)之后写一篇讲解。

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define R register
    
    using namespace std;
    
    const int maxn= 1e5+8;
    
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    
    struct Trie
    {
    	int root[maxn],ch[maxn*35][2],tot,cnt[maxn*35];
    	Trie(){root[0]=tot=1;}
    	inline void insert(int lastroot,int &nowroot,int x)
    	{
    		nowroot=++tot;
    		int u=nowroot;
    		for(R int i=30;~i;i--)
    		{
    			R int bit=(x>>i)&1;
    			ch[u][!bit]=ch[lastroot][!bit];
    			ch[u][bit]=++tot;
    			u=ch[u][bit];
    			lastroot=ch[lastroot][bit];
    			cnt[u]=cnt[lastroot]+1;
    		}
    	}
    	
    	inline int query(int l,int r,int x)
    	{
    		int res=0;
    		for(R int i=30;~i;i--)
    		{
    			R int bit=(x>>i)&1;
    			if(cnt[ch[r][!bit]]-cnt[ch[l][!bit]])
    			{
    				r=ch[r][!bit];
    				l=ch[l][!bit];
    				res+=(1<<i);
    			}
    			else
    			{
    				r=ch[r][bit];
    				l=ch[l][bit];
    			}
    		}
    		return res;
    	}
    }tr,se;
    
    int dfn[maxn],fdfn[maxn],val[maxn],idx,depth[maxn];
    
    int head[maxn],tot,l[maxn],r[maxn],size[maxn];
    struct cod{int u,v;}edge[maxn<<1];
    
    inline void add(R int x,R int y)
    {
    	edge[++tot].u=head[x];
    	edge[tot].v=y;
    	head[x]=tot;
    }
    
    int f[maxn][21];
    
    void dfs(R int u,R int fa)
    {
    	tr.insert(tr.root[fa],tr.root[u],val[u]);
    	f[u][0]=fa;depth[u]=depth[fa]+1;
    	dfn[u]=++idx,fdfn[idx]=u;size[u]=1;
    	for(R int i=1;(1<<i)<=depth[u];i++)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(R int i=head[u];i;i=edge[i].u)
    	{
    		if(edge[i].v==fa)continue;
    		dfs(edge[i].v,u);
    		size[u]+=size[edge[i].v];
    	}
    }
    
    inline int lca(R int x,R int y)
    {
    	if(depth[x]>depth[y])swap(x,y);
    	for(R int i=17;~i;i--)
    		if(depth[x]+(1<<i)<=depth[y])
    			y=f[y][i];
    	if(x==y)return y;
    	for(R int i=17;~i;i--)
    	{
    		if(f[x][i]==f[y][i])continue;
    		x=f[x][i],y=f[y][i];
    	}
    	return f[x][0];
    }
    
    int n,q;
    
    int main()
    {
    	in(n),in(q);
    	for(R int i=1;i<=n;i++)in(val[i]);
    	for(R int i=1,x,y;i<n;i++)
    	{
    		in(x),in(y);
    		add(x,y),add(y,x);
    	}
    	dfs(1,0);
    	for(R int i=1;i<=n;i++)
    		se.insert(se.root[i-1],se.root[i],val[fdfn[i]]);
    	for(R int opt,x,y,z;q;q--)
    	{
    		in(opt);
    		if(opt==1)
    		{
    			in(x),in(y);
    			printf("%d
    ",se.query(se.root[dfn[x]-1],se.root[dfn[x]+size[x]-1],y));
    		}
    		else
    		{
    			in(x),in(y),in(z);
    			int la=lca(x,y);
    			printf("%d
    ",max(tr.query(tr.root[f[la][0]],tr.root[x],z),tr.query(tr.root[f[la][0]],tr.root[y],z)));
    		}
    	}
    }
    
  • 相关阅读:
    抽象工厂模式
    python 工厂方法
    采用__call__ 实现装饰器模式
    策略模式
    采集15个代理IP网站,打造免费代理IP池
    grid网格布局——色子布局
    观察者模式
    搭建免费代理池---采集代理(1)
    python 爬虫 user-agent 生成
    多进程 + 多线程抓取博客园信息
  • 原文地址:https://www.cnblogs.com/-guz/p/9877455.html
Copyright © 2011-2022 走看看