zoukankan      html  css  js  c++  java
  • [BZOJ2908]又是nand

    Description
    首先知道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的费用。
    请众神给出一个程序支持这些操作。

    Input
    第一行N,M,K,树的节点数量、总操作个数和运算位数。
    接下来一行N个数字,依次表示节点i的权值。
    接下来N-1行,每行两个数字a,b(1≤a,b≤N)表示a,b间有一条树边。
    接下来M行,每行一个操作,为以上2类操作之一。
    N、M≤100000,K≤32

    Output
    对于操作②每个输出一行,如题目所述。

    Sample Input
    3 3 3
    2 7 3
    1 2
    2 3
    Query 2 3
    Replace 1 3
    Query 1 1

    Sample Output
    4
    7


    这题思维难度挺大。。。因为nand不满足结合律,所以甚是难受。。。
    但是网上介绍了一个叫做拆位的方法
    首先树链剖分,然后对于每一位,都用线段树维护tl[t][p],代表如果该位是t,从左边过来这个区间后会变成什么数;tr[t][p]代表如果该位是t,从右边过来这个区间后会变成什么数,然后就可以从a到lca再到b询问就好了

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)     print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5,K=33;
    int ID[N+10],dfn[N+10],n,m,k;
    ui v[N+10];
    struct Segment{
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	bool tr[2][(N<<2)+10],tl[2][(N<<2)+10];
    	void updata(int p){
    		tl[0][p]=tl[tl[0][ls]][rs],tr[0][p]=tr[tr[0][rs]][ls];
    		tl[1][p]=tl[tl[1][ls]][rs],tr[1][p]=tr[tr[1][rs]][ls];
    	}
    	void build(int p,int l,int r,int x){
    		if (l==r){
    			tl[0][p]=1,tl[1][p]=!((v[dfn[l]]>>x)&1);
    			tr[0][p]=1,tr[1][p]=!((v[dfn[l]]>>x)&1);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(ls,l,mid,x),build(rs,mid+1,r,x);
    		updata(p);
    	}
    	void change(int p,int l,int r,int x,bool v){
    		if (l==r){
    			tl[0][p]=1,tl[1][p]=!v;
    			tr[0][p]=1,tr[1][p]=!v;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if (x<=mid)	change(ls,l,mid,x,v);
    		else	change(rs,mid+1,r,x,v);
    		updata(p);
    	}
    	bool ql(int p,int l,int r,int x,int y,bool z){
    		if (x<=l&&r<=y)	return tl[z][p];
    		int mid=(l+r)>>1;
    		if (y<=mid)	return ql(ls,l,mid,x,y,z);
    		if (x>mid)	return ql(rs,mid+1,r,x,y,z);
    		return ql(rs,mid+1,r,x,y,ql(ls,l,mid,x,y,z));
    	}
    	bool qr(int p,int l,int r,int x,int y,int z){
    		if (x<=l&&r<=y)	return tr[z][p];
    		int mid=(l+r)>>1;
    		if (y<=mid)	return qr(ls,l,mid,x,y,z);
    		if (x>mid)	return qr(rs,mid+1,r,x,y,z);
    		return qr(ls,l,mid,x,y,qr(rs,mid+1,r,x,y,z));
    	}
    }Tree[K];
    struct S1{
    	int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,cnt;
    	int fa[N+10],size[N+10],deep[N+10],top[N+10],Rem[N+10],stack[N+10];
    	void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    	void insert(int x,int y){join(x,y),join(y,x);}
    	void dfs1(int x,int Deep){
    		deep[x]=Deep,size[x]=1;
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x])	continue;
    			fa[son]=x;
    			dfs1(son,Deep+1);
    			size[x]+=size[son];
    			if (size[Rem[x]]<size[son])	Rem[x]=son;
    		}
    	}
    	void dfs2(int x){
    		if (!x)	return;
    		dfn[ID[x]=++cnt]=x;
    		top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
    		dfs2(Rem[x]);
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x]||son==Rem[x])	continue;
    			dfs2(son);
    		}
    	}
    	void work(int x,int y){
    		ui res=0; int Top=0;
    		while (top[x]!=top[y]){
    			if (deep[top[x]]>=deep[top[y]]){
    				for (int i=0;i<k;i++)	res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[top[x]],ID[x],(res>>i)&1)<<i);
    				x=fa[top[x]];
    			}else	stack[++Top]=y,y=fa[top[y]];
    		}
    		for (int i=0;i<k;i++){
    			if (deep[x]<deep[y])	res=res-(res&(1<<i))+(Tree[i].ql(1,1,n,ID[x],ID[y],(res>>i)&1)<<i);
    			else	res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[y],ID[x],(res>>i)&1)<<i);
    		}
    		for (int i=Top;i;i--)	for (int j=0;j<k;j++)	res=res-(res&(1<<j))+(Tree[j].ql(1,1,n,ID[top[stack[i]]],ID[stack[i]],(res>>j)&1)<<j);
    		printf("%u
    ",res);
    	}
    }T;
    int main(){
    	n=read(),m=read(),k=read();
    	for (int i=1;i<=n;i++)	scanf("%u",&v[i]);
    	for (int i=1;i<n;i++){
    		int x=read(),y=read();
    		T.insert(x,y);
    	}
    	T.dfs1(1,1),T.dfs2(1);
    	for (int i=0;i<k;i++)	Tree[i].build(1,1,n,i);
    	char s[10];
    	for (int i=1;i<=m;i++){
    		scanf("%s",s);
    		if (s[0]=='R'){
    			int x=read();scanf("%u",&v[x]);
    			for (int j=0;j<k;j++)	Tree[j].change(1,1,n,ID[x],(v[x]>>j)&1);
    		}
    		if (s[0]=='Q'){
    			int x=read(),y=read();
    			T.work(x,y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    SAP MM 有了采购订单历史的PO行项目里的采购附加费不允许再改了?
    风之语.人在职场也需要'备胎'
    两万字,任正非采访全记录
    SAP 如何得到交货单上的序列号清单?
    【2019年版】如何向SAP公司提交Message?
    工作上996,生活上669,并不是什么难事儿!
    风之语.甲骨文裁员之我见
    天河2号-保持使用yhrun/srun时连接不中断 (screen 命令教程 )
    PXE 和 计算机网络启动
    Gmail 设置,时区
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9459821.html
Copyright © 2011-2022 走看看