• BZOJ2908 又是nand


    题意

    首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5。
    给出一棵树,树上每个点都有点权,定义树上从a到b的费用为0与路径上的点的权值顺次nand的结果,例如:从2号点到5号点顺次经过2->3->5,权值分别为5、7、2,K=3,那么最终结果为0 nand 5 nand 7 nand 2=7 nand 7 nand 2=0 nand 2=7,现在这棵树需要支持以下操作。
    ① Replace a b:将点a(1≤a≤N)的权值改为b。
    ② Query a b:输出点a到点b的费用。
    请众神给出一个程序支持这些操作。

    N、M≤100000,K≤32

    分析

    参照CQzhangyu的题解。

    网上都说要拆位,那么我也拆位吧~(不拆位好像也能做?)

    首先,nand不满足交换律或结合律。

    我们先树剖,然后对于每一位,都用线段树维护tl[d][x],代表如果该位是d,从左边来经过这个区间后会变成的数,tr[d][x]代表如果该位是d,从右往左经过这个区间后会变成的数。然后就是区间合并的事了~

    对于询问a,b,我们先求出从a向上走到lca的变化,再求出从lca向下走到b的变化即可。

    时间复杂度(O(n+mlog^2 n))

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    #define lson x<<1
    #define rson x<<1|1
    template<class T>il T read(){
    	rg T data=0,w=1;
    	rg char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    		data=data*10+ch-'0',ch=getchar();
    	return data*w;
    }
    template<class T>il T read(rg T&x){
    	return x=read<T>();
    }
    typedef long long ll;
    
    int n,m,k,cnt;
    char str[10];
    co int N=1e5+1;
    int to[N*2],next[N*2],head[N],fa[N],dep[N],siz[N],top[N],son[N],p[N],q[N],st[N];
    unsigned v[N];
    struct seg{
    	bool tl[2][N*4],tr[2][N*4];
    	void pushup(int x){
    		tl[0][x]=tl[tl[0][lson]][rson],tl[1][x]=tl[tl[1][lson]][rson];
    		tr[0][x]=tr[tr[0][rson]][lson],tr[1][x]=tr[tr[1][rson]][lson];
    	}
    	void build(int l,int r,int x,int a){
    		if(l==r){
    			tl[0][x]=tr[0][x]=1,tl[1][x]=tr[1][x]=!(v[q[l]]>>a&1);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(l,mid,lson,a),build(mid+1,r,rson,a);
    		pushup(x);
    	}
    	void updata(int l,int r,int x,int a,bool b){
    		if(l==r){
    			tl[0][x]=tr[0][x]=1,tl[1][x]=tr[1][x]=!b;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(a<=mid) updata(l,mid,lson,a,b);
    		else updata(mid+1,r,rson,a,b);
    		pushup(x);
    	}
    	bool ql(int l,int r,int x,int a,int b,bool c){
    		if(a<=l&&r<=b) return tl[c][x];
    		int mid=(l+r)>>1;
    		if(b<=mid) return ql(l,mid,lson,a,b,c);
    		if(a>mid) return ql(mid+1,r,rson,a,b,c);
    		return ql(mid+1,r,rson,a,b,ql(l,mid,lson,a,b,c));
    	}
    	bool qr(int l,int r,int x,int a,int b,bool c){
    		if(a<=l&&r<=b) return tr[c][x];
    		int mid=(l+r)>>1;
    		if(b<=mid) return qr(l,mid,lson,a,b,c);
    		if(a>mid) return qr(mid+1,r,rson,a,b,c);
    		return qr(l,mid,lson,a,b,qr(mid+1,r,rson,a,b,c));
    	}
    }s[33];
    void dfs1(int x){
    	siz[x]=1;
    	for(int i=head[x];i;i=next[i]){
    		if(to[i]==fa[x]) continue;
    		fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];
    		if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
    	}
    }
    void dfs2(int x,int tp){
    	top[x]=tp,p[x]=++p[0],q[p[0]]=x;
    	if(!son[x]) return;
    	dfs2(son[x],tp);
    	for(int i=head[x];i;i=next[i]){
    		if(to[i]==fa[x]||to[i]==son[x]) continue;
    		dfs2(to[i],to[i]);
    	}
    }
    void add(int a,int b){
    	to[++cnt]=b,next[cnt]=head[a],head[a]=cnt;
    	to[++cnt]=a,next[cnt]=head[b],head[b]=cnt;
    }
    void ask(int x,int y){
    	unsigned ans=0;
    	st[0]=0;
    	while(top[x]!=top[y]){
    		if(dep[top[x]]>=dep[top[y]]){
    			for(int i=0;i<k;++i)
    				ans=ans-(ans&(1<<i))+(s[i].qr(1,n,1,p[top[x]],p[x],ans>>i&1)<<i);
    			x=fa[top[x]];
    		}
    		else st[++st[0]]=y,y=fa[top[y]];
    	}
    	if(dep[x]<dep[y])
    		for(int i=0;i<k;++i)
    			ans=ans-(ans&(1<<i))+(s[i].ql(1,n,1,p[x],p[y],ans>>i&1)<<i);
    	else
    		for(int i=0;i<k;++i)
    			ans=ans-(ans&(1<<i))+(s[i].qr(1,n,1,p[y],p[x],ans>>i&1)<<i);
    	for(y=st[0];y;--y)
    		for(int i=0;i<k;++i)
    			ans=ans-(ans&(1<<i))+(s[i].ql(1,n,1,p[top[st[y]]],p[st[y]],ans>>i&1)<<i);
    	printf("%u
    ",ans);
    }
    int main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n),read(m),read(k);
    	for(int i=1;i<=n;++i)
    		read(v[i]);
    	for(int i=1;i<n;++i)
    		add(read<int>(),read<int>());
    	dep[1]=1,dfs1(1),dfs2(1,1);
    	for(int i=0;i<k;++i)
    		s[i].build(1,n,1,i);
    	for(int i=1;i<=m;++i){
    		scanf("%s",str);
    		if(str[0]=='Q'){
    			int a=read<int>(),b=read<int>();
    			ask(a,b);
    		}
    		else{
    			int a=read<int>();read(v[a]);
    			for(int j=0;j<k;++j)
    				s[j].updata(1,n,1,p[a],v[a]>>j&1);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#
    C#
    C#
    C#
    C#
    C#
    系统工具
    远程登录
    文件传输服务
    软件安装
  • 原文地址:https://www.cnblogs.com/autoint/p/10408492.html
Copyright © 2020-2023  润新知