• 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类操作之一。
     

    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

    HINT

    100%的数据N、M≤100000,K≤32


    我们发现nand这个东西啊,excited。。。
    既没有结合律又没有交换律。
    考虑一般算法,按位拆分,分别维护0依次nand的结果,1依次nand的结构,然后就可以合并了。
    因为要考虑方向所以线段树从前到后的nand和从后往前的nand都需要维护。
    然后讨论讨论套上树链剖分就行了。
    时间复杂度每次O(log^3N)。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
    	if(head==tail) {
    		int l=fread(buffer,1,BufferSize,stdin);
    		tail=(head=buffer)+l;
    	}
    	return *head++;
    }
    typedef unsigned int uint;
    inline uint read() {
        uint x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=100010;
    int n,m,k,first[maxn],next[maxn<<1],to[maxn<<1],e;
    void AddEdge(int u,int v) {
    	to[++e]=v;next[e]=first[u];first[u]=e;
    	to[++e]=u;next[e]=first[v];first[v]=e;
    }
    int fa[maxn],son[maxn],siz[maxn],dep[maxn];
    void dfs(int x) {
    	dep[x]=dep[fa[x]]+1;siz[x]=1;
    	ren if(to[i]!=fa[x]) {
    		fa[to[i]]=x;dfs(to[i]);
    		siz[x]+=siz[to[i]];if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
    	}
    }
    int top[maxn],pos[maxn],cnt;
    void build(int x,int tp) {
    	top[x]=tp;pos[x]=++cnt;
    	if(son[x]) build(son[x],tp);
    	ren if(to[i]!=fa[x]&&to[i]!=son[x]) build(to[i],to[i]);
    }
    int lca(int x,int y) {
    	int f1=top[x],f2=top[y];
    	while(f1!=f2) {
    		if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
    		x=fa[f1];f1=top[x];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    struct Node {
    	uint sum0,sum1;
    }T[maxn<<2],T2[maxn<<2];
    uint all,val[maxn];
    uint nand(uint x,uint y) {return (x&y)^all;}
    Node operator + (Node A,Node B) {
    	Node C;C.sum0=C.sum1=0;
    	rep(i,0,k-1) {
    		if(A.sum0>>i&1) {
    			if(B.sum1>>i&1) C.sum0|=1u<<i;
    		}
    		else {
    			if(B.sum0>>i&1) C.sum0|=1u<<i;
    		}
    		if(A.sum1>>i&1) {
    			if(B.sum1>>i&1) C.sum1|=1u<<i;
    		}
    		else {
    			if(B.sum0>>i&1) C.sum1|=1u<<i;
    		}
    	}
    	return C;
    }
    void maintain(int o) {
    	int lc=o<<1,rc=lc|1;
    	T[o]=T[lc]+T[rc];
    	T2[o]=T2[rc]+T2[lc];
    }
    void update(int o,int l,int r,int p,uint v) {
    	if(l==r) T[o]=T2[o]=(Node){nand(0,v),nand(all,v)};
    	else {
    		int mid=l+r>>1,lc=o<<1,rc=lc|1;
    		if(p<=mid) update(lc,l,mid,p,v);
    		else update(rc,mid+1,r,p,v);
    		maintain(o);
    	}
    }
    Node ans;
    int flag;
    void query(int o,int l,int r,int ql,int qr,int tp) {
    	if(ql<=l&&r<=qr) {
    		if(!flag) ans=(!tp?T[o]:T2[o]),flag=1;
    		else ans=ans+(!tp?T[o]:T2[o]);
    	}
    	else {
    		int mid=l+r>>1,lc=o<<1,rc=lc|1;
    		if(!tp) {
    			if(ql<=mid) query(lc,l,mid,ql,qr,tp);
    			if(qr>mid) query(rc,mid+1,r,ql,qr,tp);
    		}
    		else {
    			if(qr>mid) query(rc,mid+1,r,ql,qr,tp);
    			if(ql<=mid) query(lc,l,mid,ql,qr,tp);
    		}
    	}
    }
    int Ql[maxn],Qr[maxn],Top;
    void query(int x,int y) {
    	int z=lca(x,y),f,ql,qr;
    	f=top[x];flag=0;
    	while(f!=top[z]) {
    		ql=pos[f];qr=pos[x];
    		query(1,1,n,ql,qr,1);
    		x=fa[f];f=top[x];
    	}
    	ql=pos[z];qr=pos[x];
    	query(1,1,n,ql,qr,1);
    	f=top[y];
    	while(f!=top[z]) {
    		ql=pos[f];qr=pos[y];
    		Ql[++Top]=ql;Qr[Top]=qr;
    		y=fa[f];f=top[y];
    	}
    	ql=pos[z]+1;qr=pos[y];
    	if(ql<=qr) Ql[++Top]=ql,Qr[Top]=qr;
    	while(Top) {
    		query(1,1,n,Ql[Top],Qr[Top],0);
    		Top--;
    	}
    	printf("%u
    ",ans.sum0);
    }
    int main() {
    	n=read();m=read();k=read();
    	rep(i,0,k-1) all|=1ll<<i;
    	rep(i,1,n) val[i]=read();
    	rep(i,2,n) AddEdge(read(),read());
    	dfs(1);build(1,1);
    	rep(i,1,n) update(1,1,n,pos[i],val[i]);
    	rep(i,1,m) {
    		char c=Getchar();while(!isalpha(c)) c=Getchar();
    		int x=read(),y=read();
    		if(c=='Q') query(x,y);
    		else update(1,1,n,pos[x],y);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    VUE前端项目配置代理解决跨域问题
    面试题:无序数组排序后的最大相邻差
    Vue项目中更改Vux组件中的样式
    iOS13适配 UITableView 种Cell出现带方框的小箭头
    JavaScript 中的require,import,export
    前端框架 Less 学习与实践
    Vue textarea 高度自适应
    Vue项目中添加手势实现左滑右滑操作
    day24 多态--后续
    day24 继承、封装和多态
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5585298.html
Copyright © 2020-2023  润新知