Luogu P11160 【MX-X6-T6】機械生命体 题解

P11160 【MX-X6-T6】機械生命体

注意到 lowbit 是从最低位开始的,所以我们把数字按照二进制位从低位往高位插进字典树。

插入和删除操作是平凡的。查最大 lowbit 只需要从根节点开始走,能走使这一位异或为 0 的边就走这一条边,否则直接返回,因为不可能有更大的 lowbit 值。

接下来考虑处理操作 3。满足要求的数字部分是容易提取的,在字典树上走使这一位异或为 0 的边,直到第 k 位。这一位对应的子树中存储的数值肯定满足要求。

然后考虑如何整体增加。我们发现对于如果字典树中的数据整体加 1,最低位为 0 的数只有最低位会变化,最低位变成 1。而最低位为 1 的数最低位变成 0,且之后高一位会增加 1。这相当于交换左右根节点儿子,并递归处理交换后的左儿子。这启发我们使用懒标记处理这个问题,上述的就是增加过程。

然而对于子树增加,这么做是困难的。因此,我们把这棵满足要求的子树和这棵子树的根到整个树的根分裂出来,打上懒标记,然后再合并回去。这么做的时间复杂度可以类比线段树合并与分裂的时间复杂度,为整体 O(nlogn)

最后考虑整体加 v。我们沿用上面的思路,对于这一位加 v 其实可以转化为对于下一位加 n2。并且如果 v 为奇数,就还需要在这一位处理一下加 1,因为这一个加 1 没有下推。

#include <bits/stdc++.h>
using namespace std;
long long q,op,k,v,x,trie[20000000][2],tol[20000000],ad[20000000],cnt=1;
void pushdown(long long x)
{
	if(ad[x]&1)swap(trie[x][0],trie[x][1]),ad[trie[x][0]]++;
	ad[trie[x][0]]+=(ad[x]>>1),ad[trie[x][1]]+=(ad[x]>>1),ad[x]=0;
}

void insert(long long x)
{
	long long rt=1;
	tol[rt]++;
	for(long long i=0;i<=32;i++)
	    {
	    	pushdown(rt);
	    	long long id=(x>>i)&1;
	    	if(!trie[rt][id])trie[rt][id]=++cnt;
	    	rt=trie[rt][id],tol[rt]++;
		}
}

void del(long long x)
{
	long long rt=1;
	tol[rt]--;
	for(long long i=0;i<=32;i++)
	    {
	    	pushdown(rt);
	    	long long id=(x>>i)&1;
	    	rt=trie[rt][id],tol[rt]--;
		}
}

long long merge(long long x,long long y)
{
	if(!x||!y)return x+y;
	pushdown(x),pushdown(y);
	tol[x]+=tol[y],trie[x][0]=merge(trie[x][0],trie[y][0]),trie[x][1]=merge(trie[x][1],trie[y][1]);
    return x;
}

void update(long long x,long long k,long long v)
{
	long long rt=1,pt=++cnt,now=pt,pr=0,prt=0,pd=0,tmp=0;
	if(k==0)
	   {
	   	pushdown(rt),ad[rt]+=v;
	   	return;
	   }
	for(long long i=0;i<k;i++)
	    {
	    	pushdown(rt);
	    	long long id=(x>>i)&1;
	    	if(!trie[rt][id]||!tol[trie[rt][id]])return;
	    	pr=rt,pd=id,prt=pt;
	    	trie[pt][id]=++cnt,rt=trie[rt][id],pt=trie[pt][id];
		}
	pushdown(rt);
	trie[pr][pd]=0,trie[prt][pd]=rt,tmp=tol[rt];
	rt=1,pt=now;
	for(long long i=0;i<k;i++)
	    {
	    	pushdown(rt);
	    	long long id=(x>>i)&1;
	    	tol[rt]-=tmp,tol[pt]=tmp;
	    	rt=trie[rt][id],pt=trie[pt][id];
		}
	ad[now]+=v,merge(1,now);
}

long long getmax(long long x)
{
	long long rt=1,mx=0;
	for(long long i=0;i<=32;i++)
	    {
	    	pushdown(rt);
	    	long long id=(x>>i)&1;
	    	if(!trie[rt][id]||!tol[trie[rt][id]])return mx;
	    	mx=max(mx,i+1),rt=trie[rt][id];
		}
	return 32;
}

int main()
{
	scanf("%d",&q);
	for(long long i=1;i<=q;i++)
	    {
	    	scanf("%lld",&op);
	    	if(op==1)scanf("%lld",&x),insert(x);
	    	else if(op==2)scanf("%lld",&x),del(x);
	    	else if(op==3)scanf("%lld%lld%lld",&x,&k,&v),update(x,k,v);
	    	else if(op==4)scanf("%lld",&x),printf("%lld\n",(1ll<<getmax(x)));
		}
	return 0;
}
posted @   w9095  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示