【洛谷】T46495 子異和 -拆位找規律&線段樹
阿新 • • 發佈:2018-11-26
傳送門:luoguT46495 子異和
題解
這題的性質和維護都很妙啊。
一個數集的子異和為其所有非空子集的集合異或和之和。
考慮如何
回答單次詢問:
拆位後用桶
表示第
位在前
個數組成的所有非空子集中出現的總次數。
可以把前 個數組成的所有非空子集分成含有 和不含有 兩部分,分別處理後加起來:
- 若當前數 二進位制第 位為 :
- 若當前數 二進位制第 位為 :
顯然能夠得到結論:集合 的子異和
對於詢問, 序+線段樹維護區間異或和即可。
為了維護每次修改後的異或和,還需要維護區間與,再深入發掘一下性質:
對於一個區間的數異或上一個 時,觀察到:
從
變成
的位必然滿足
的二進位制對應位為
,且區間或值對應位為
。
從
變成
的位必然滿足
的二進位制對應位為
,且區間與值對應位為
。
這樣維護就好了。
程式碼
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define lc k<<1
#define rc k<<1|1
using namespace std;
typedef long long ll;
const int N=2e5+100,mod=1e9+7;
const int maxn=(1LL<<31)-1;
int n,m,val[N],bin[N];
int head[N],to[N<<1],nxt[N<<1],tot;
int df[N],top[N],sz[N],son[N],f[N],dep[N],dfn;
int qx[N<<2],qy[N<<2],lzy[N<<2];
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
char cp,SS[100];
template<class yyy>
inline void rd(yyy &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
inline void ot(int x)
{
int re=0;
for(;(!re)||(x);x/=10) SS[++re]='0'+x%10;
for(;re;--re) putchar(SS[re]);
putchar('\n');
}
void dfs(int x)
{
sz[x]=1;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x]) continue;
f[j]=x;dep[j]=dep[x]+1;dfs(j);
sz[x]+=sz[j];if(sz[son[x]]<sz[j]) son[x]=j;
}
}
void dfss(int x,int tpo)
{
top[x]=tpo;df[x]=++dfn;
if(!son[x]) return;
dfss(son[x],tpo);
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x] || j==son[x]) continue;
dfss(j,j);
}
}
void build(int k,int l,int r)
{
if(l==r) {qx[k]=qy[k]=val[l];return;}
build(lc,l,mid);build(rc,mid+1,r);
qx[k]=qx[lc]|qx[rc];
qy[k]=qy[lc]&qy[rc];
}
inline void trs(int k,int v)
{
lzy[k]^=v;int x=qx[k],y=qy[k];
x^=(qy[k]&v);x|=((maxn^qy[k])&v);
y^=(qy[k]&v);y|=((maxn^qx[k])&v);
qx[k]=x;qy[k]=y;
}
inline void pushdown(int k)
{
if(!lzy[k]) return;
trs(lc,lzy[k]);trs(rc,lzy[k]);
lzy[k]=0;
}
int gt(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) return qx[k];
pushdown(k);
if(R<=mid) return gt(lc,l,mid,L,R);
if(L>mid) return gt(rc,mid+1,r,L,R);
qx[k]=qx[lc]|qx[rc];
qy[k]=qy[lc]&qy[rc];
return (gt(lc,l,mid,L,R)|gt(rc,mid+1,r,L,R));
}
void modify(int k,int l,int r,int L,int R,int v)
{
if(L<=l && r<=R){trs(k,v);return;}
pushdown(k);
if(L<=mid) modify(lc,l,mid,L,R,v);
if(R>mid) modify(rc,mid+1,r,L,R,v);
qx[k]=qx[lc]|qx[rc];
qy[k]=qy[lc]&qy[rc];
}
inline int ask(int x,int y)
{
int re=0,cot=-1;
for(;top[x]!=top[y];x=f[top[x]]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
cot+=(dep[x]-dep[top[x]]+1);
re|=gt(1,1,n,df[top[x]],df[x]);
}
if(dep[x]<dep[y]) swap(x,y);
cot+=(dep[x]-dep[y]+1);
re|=gt(1,1,n,df[y],df[x]);
return (ll)re*bin[cot]%mod;
}
inline void cg(int x,int y,int z)
{
for(;top[x]!=top[y];x=f[top[x]]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(1,1,n,df[top[x]],df[x],z);
}
if(dep[x]<dep[y]) swap(x,y);
modify(1,1,n,df[y],df[x],z);
}
int main(){
int i,j,op,x,y,z;
rd(n);rd(m);
for(i=1;i<n;++i){
rd(x);rd(y);lk(x,y);lk(y,x);
}
bin[0]=1;for(i=1;i<=n;++i) bin[i]=ad(bin[i-1],bin[i-1]);
dep[1]=1;dfs(1);dfss(1,1);
for(i=1;i<=n;++i) rd(val[df[i]]);
build(1,1,n);
for(;m;--m){
rd(op);rd(x);rd(y);
if(op==1) ot(ask(x,y));
else{rd(z);cg(x,y,z);}
}
return 0;
}