zoukankan      html  css  js  c++  java
  • 【LGP5127】子异和

    题目

    子异和这个名字,真是思博

    显然一个集合的子集异或和为,(2^{|S|-1} imes A)(A)为集合的或和

    于是现在的问题变成了树链异或一个数,求树链或和

    显然强行拆位是可以做的,复杂度(O(nlog n log mod)),还是( m lct)于是直接飞了

    通过一番玄妙重重的推理,我们发现,整体异或上(c),对或和的影响是

    [cup'=(cup&∼c)|(c&∼cap) ]

    这样我们还需要维护与和

    [cap'=(cap&∼c)|(c&∼cup) ]

    直接( m lct)维护即可,注意维护与和的时候记得判断当左右儿子为空时就不要取与了

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    const int mod=1e9+7;
    const int maxn=2e5+5;
    #pragma GCC optimize(3)
    #pragma GCC optimize("-fcse-skip-blocks")
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    unsigned int v[2][maxn],s[2],tag[maxn];
    int ch[maxn][2],fa[maxn],sz[maxn],rev[maxn],st[maxn],a[maxn];
    int xx[maxn],yy[maxn],pw[maxn],n,Q;
    inline int nrt(int x) {return x==ch[fa[x]][0]||x==ch[fa[x]][1];}
    inline void pushup(int x) {
    	sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];
    	v[1][x]=v[0][x]=a[x];
    	v[0][x]|=(v[0][ch[x][0]]|v[0][ch[x][1]]);
    	if(ch[x][0]) v[1][x]=(v[1][x]&v[1][ch[x][0]]);
    	if(ch[x][1]) v[1][x]=(v[1][x]&v[1][ch[x][1]]);
    }
    inline void calc(int x,unsigned int c) {
    	if(!x) return;
    	a[x]^=c,tag[x]^=c;
    	s[0]=v[0][x],s[1]=v[1][x];
    	v[0][x]=(s[0]&~c)|(c&~s[1]);
    	v[1][x]=(s[1]&~c)|(c&~s[0]);
    }
    inline void pushdown(int x) {
    	if(tag[x]) {
    		calc(ch[x][0],tag[x]),calc(ch[x][1],tag[x]);
    		tag[x]=0;
    	} 
    	if(rev[x]) {
    		rev[x]=0,rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
    		std::swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
    		std::swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
    	}
    }
    inline void rotate(int x) {
    	int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][k^1];
    	if(nrt(y)) ch[z][ch[z][1]==y]=x;
    	ch[x][k^1]=y,ch[y][k]=w;
    	pushup(y),pushup(x);fa[w]=y,fa[y]=x,fa[x]=z;
    }
    inline void splay(int x) {
    	int y=x,top=0;st[++top]=x;
    	while(nrt(y)) y=fa[y],st[++top]=y;
    	while(top) pushdown(st[top--]);
    	while(nrt(x)) {
    		int y=fa[x];
    		if(nrt(y)) rotate((ch[y][1]==x)^(ch[fa[y]][1]==y)?x:y);
    		rotate(x);
    	}
    }
    inline void access(int x) {
    	for(re int y=0;x;y=x,x=fa[x])
    		splay(x),ch[x][1]=y,pushup(x);
    }
    inline void mrt(int x) {
    	access(x),splay(x),rev[x]^=1;std::swap(ch[x][0],ch[x][1]);
    }
    inline void split(int x,int y) {
    	mrt(x),access(y),splay(y);
    }
    inline void link(int x,int y) {
    	mrt(x),fa[x]=y;
    }
    int main() {
    	n=read();Q=read();
    	for(re int i=1;i<n;i++) xx[i]=read(),yy[i]=read();
    	for(re int i=1;i<=n;i++) a[i]=read(),sz[i]=1;
    	for(re int i=1;i<n;i++) link(xx[i],yy[i]);
    	pw[0]=1;int x,y,op;unsigned int c;
    	for(re int i=1;i<=n;++i) pw[i]=(pw[i-1]+pw[i-1])%mod;
    	while(Q--) {
    		op=read();x=read(),y=read();split(x,y);
    		if(op==1) printf("%d
    ",1ll*v[0][y]%mod*pw[sz[y]-1]%mod);
    		else c=read(),calc(y,c);
    	}
    	return 0;
    }
    
  • 相关阅读:
    码到成功——冲刺随笔 day 8
    码到成功——冲刺随笔 day 7
    码到成功——冲刺随笔 day 6
    码到成功——冲刺随笔 day 5
    码到成功——冲刺随笔 day 4
    码到成功——冲刺随笔 day 3
    码到成功——冲刺随笔 day 2
    Alpha冲刺 —— 5.9
    Alpha冲刺 —— 5.8
    Alpha冲刺 —— 5.7
  • 原文地址:https://www.cnblogs.com/asuldb/p/11477946.html
Copyright © 2011-2022 走看看