zoukankan      html  css  js  c++  java
  • 【BZOJ2908】 又是nand

    又是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的费用。

    请给出一个程序支持这些操作。

    Solution

    好像是个板子,然后发现nand不满足交换律和结合律

    艹!那拿头维护啊!

    我们考虑对于二进制位每一位种一棵线段树,然后每个节点({l,r}),维护(0 nand {l,r})的值,(1 nand {l,r})的值,({l,r} nand 0)({l,r} nand 1)的值(都只是这一位上)

    然后每次找到a、b的lca,然后对于a到lca上的路径,从右到左查询,然后lca到b,从左到右查询(因为a、b的id均比lca大),记得两边查询不能两边重复查lca,然后两个合并一下就好了

    记住query的时候从右到左时要先访问右儿子再访问左儿子。。。我因为这个居然调了1h+。。。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    struct qwq{
    	int v;
    	int nxt;
    }edge[200010];
    int cnt=-1;
    int head[200010];
    void add(int u,int v){
    	edge[++cnt].nxt=head[u];
    	edge[cnt].v=v;
    	head[u]=cnt;
    }
    int fa[200010];
    int son[200010];
    int top[200010];
    int siz[200010];
    int tid[200010];
    int dep[200010];
    int ind;
    void dfs1(int u,int ff,int depth){
    	fa[u]=ff;
    	siz[u]=1;
    	dep[u]=depth;
    	for(int i=head[u];~i;i=edge[i].nxt){
    		int v=edge[i].v;
    		if(v==ff)continue;
    		dfs1(v,u,depth+1);
    		siz[u]+=siz[v];
    		if(!son[u]||siz[son[u]]<siz[v])son[u]=v;
    	}
    } 
    void dfs2(int u,int topf){
    	tid[u]=++ind;
    	top[u]=topf;
    	if(son[u]){
    		dfs2(son[u],topf);
    	} 
    	for(int i=head[u];~i;i=edge[i].nxt){
    		int v=edge[i].v;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    bool t[800010][33][2][2];//[0][0]:左,0 
    int k;
    #define ls o<<1
    #define rs o<<1|1
    void pushup(int o){
    	for(int i=0;i<=k;++i){
    		t[o][i][0][0]=t[rs][i][0][t[ls][i][0][0]];
    		t[o][i][0][1]=t[rs][i][0][t[ls][i][0][1]];
    		t[o][i][1][0]=t[ls][i][1][t[rs][i][1][0]];
    		t[o][i][1][1]=t[ls][i][1][t[rs][i][1][1]];
    	}
    }
    void update(int o,int l,int r,int x,int val){
    	if(l==r){
    		int tmp=1;
    		for(int i=0;i<=k;++i){
    			if((val&tmp)==tmp){
    				t[o][i][0][0]=1;
    				t[o][i][0][1]=0;
    				t[o][i][1][0]=1;
    				t[o][i][1][1]=0;
    			}
    			else {
    				t[o][i][0][0]=t[o][i][0][1]=t[o][i][1][0]=t[o][i][1][1]=1;
    			}
    			tmp<<=1;
    		}
    		return;
    	}
    	int mid=(l+r)/2;
    	if(x<=mid)update(ls,l,mid,x,val);
    	else update(rs,mid+1,r,x,val);
    	pushup(o);
    }
    int ans[33];
    void upd(int o,int type){
    	for(int i=0;i<=k;++i){
    		ans[i]=t[o][i][type][ans[i]];
    	}
    }
    void query(int o,int l,int r,int L,int R,int type){
    	if(L>R)return;
    	if(L<=l&&r<=R){
    		upd(o,type);
    		return;
    	}
    	int mid=(l+r)/2;
    	if(type==1){
    		if(mid<R)query(rs,mid+1,r,L,R,type);
    		if(L<=mid)query(ls,l,mid,L,R,type);
    	}
    	else {
    		if(L<=mid)query(ls,l,mid,L,R,type);
    		if(mid<R)query(rs,mid+1,r,L,R,type);
    	}
    }
    int lca(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		x=fa[top[x]];
    	}
    	if(dep[x]>dep[y])swap(x,y);
    	return x;
    }
    int n,m;
    void querytree1(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		query(1,1,n,tid[top[x]],tid[x],1);
    		x=fa[top[x]];
    	}
    	if(dep[x]<dep[y])swap(x,y);
    	query(1,1,n,tid[y],tid[x],1);
    }
    struct qq{
    	int l,r;
    }stk[200010];
    int tp;
    void querytree2(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		stk[++tp].l=tid[top[x]],stk[tp].r=tid[x];
    		x=fa[top[x]];
    	}
    	if(dep[x]<dep[y])swap(x,y);
    	stk[++tp].l=tid[y]+1,stk[tp].r=tid[x];
    }
    int v[200010];
    signed main(){
    	memset(head,-1,sizeof(head));
    	scanf("%lld%lld%lld",&n,&m,&k);
    	k--; 
    	for(int i=1;i<=n;++i){
    		scanf("%lld",&v[i]);
    	}
    	for(int i=1;i<n;++i){
    		int u,v;
    		scanf("%lld%lld",&u,&v);
    		add(u,v),add(v,u);
    	}
    	dfs1(1,0,1);
    	dfs2(1,1);
    	for(int i=1;i<=n;++i){
    		update(1,1,n,tid[i],v[i]);
    	}
    	char que[21];
    	for(int i=1;i<=m;++i){
    		scanf("%s",que);
    		if(que[0]=='Q'){
    			int x,y;
    			scanf("%lld%lld",&x,&y);
    			int LCA=lca(x,y);
    			querytree1(x,LCA);
    			querytree2(y,LCA);
    			for(int j=tp;j>=1;--j)query(1,1,n,stk[j].l,stk[j].r,0);
    			tp=0;
    			int tmp=0;
    			for(int j=0;j<=k;++j){
    				tmp+=ans[j]<<j;
    			}
    			printf("%lld
    ",tmp);
    			memset(ans,0,sizeof(ans));
    		}
    		else {
    			int u,val;
    			scanf("%lld%lld",&u,&val);
    			update(1,1,n,tid[u],val);
    		}
    	}
    }
    
  • 相关阅读:
    Java读写文本文件操作
    java常用的文件读写操作
    CentOS yum 源的配置与使用
    每天一个linux命令目录
    Linux的概念与体系
    linux ACL权限规划:getfacl,setfacl使用
    基于大数据的电影网站项目开发之HBase分布式安装(四)
    基于大数据的电影网站项目开发之阶段性总结(三)
    基于大数据的电影网站项目开发之Hadoop2.6.0伪分布式设置(二)
    基于大数据的电影网站项目开发之CentOS的安装(一)
  • 原文地址:https://www.cnblogs.com/youddjxd/p/11626903.html
Copyright © 2011-2022 走看看