异或矩阵
使用 库默尔定理 发现,如果 \(y-x\subseteq k-1\) 那么 \((1,y)\) 将向 \((k,x)\) 造成贡献
考虑当 \(k=2^x\) 时转移只有两个地方是子集,那么分 \(\log\) 步迭代完成转移即可
Code Display
const int N=3e6+10;
unsigned int a[N],f[N];
int n,k;
signed main(){
freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout);
n=read(); k=read(); a[1]=read<ui>();
for(int i=2;i<=n;++i) a[i]=1145141*a[i-1]+(ui)1919*i+810;
for(int i=0;i<23;++i) if((k-1)>>i&1){
for(int j=1;j+(1<<i)<=n;++j) a[j]^=a[j+(1<<i)];
}
ui ans=0;
for(int i=1;i<=n-k+1;++i) ans=ans+i*(a[i]^i);
print(ans);
return 0;
}
树
点集 \(\rm LCA\) 是子树的根等价于从不少于 \(2\) 个子树里面选点或者选择它本身
使用容斥原理即可
感觉 xzh 同学这种明显的恶意不取模行为是十分强大的
Code Display
const int N=1e5+10;
int siz[N],ans[N],n;
vector<int> G[N];
inline void dfs(int x,int fat){
siz[x]=1; ans[x]=mod-1;
for(auto t:G[x]) if(t!=fat){
dfs(t,x); siz[x]+=siz[t];
ckdel(ans[x],del(ksm(2,siz[t]),1));
}
ckadd(ans[x],ksm(2,siz[x]));
}
signed main(){
freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
n=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs(1,0);
for(int i=1;i<=n;++i) print(ans[i]);
return 0;
}
黑白树
考虑线段树历史有条件最值的一种计算方式:在 push_down
时如果满足条件再转移到两个子区间里面,push_up
时如果子区间和母区间的条件一致再进行信息的维护
那么本题中的 “条件” 就是两个点处在同色联通块中,而判定条件就是 两个点颜色相同 并且 根链上的异色点数量 相同
将每个同色联通块的信息都挂到联通块中深度最小的点上面,求得这个点具体是谁可以使用 重链剖分 配合 std::set
来实现找到根链上第一个异色点再跳儿子即可
将线段树上某个区间管辖点视作其所有点的 \(\rm LCA\),维护如下信息:
-
cnt[0/1]
表示两个颜色点数 -
Mx[0/1]
表示两种颜色联通块中的最值 -
cnt_tag[0/1],col_tag[0/1],tag
分别表示三种懒标记:点数修改,同色权值加,子树/链 加
在进行区间修改的时候先查询联通块最浅点的 cnt
信息,再对其进行子树加即可,注意 \(\rm DFS\) 序区间上不满足 cnt
值相同的区间不能放懒标记
实现的时候注意维护当前信息需要的是哪种颜色以及 push_down
时信息下放的顺序:异色点数要在同色联通块加之前来保证正确性
Code Display
const int N=2e5+10,inf=0x3f3f3f3f3f3f3f3f;
int dfn[N],ord[N],top[N],son[N],siz[N],dep[N],fa[N],tim;
vector<int> G[N];
int n,Q,col[N];
inline void dfs1(int x,int fat){
dep[x]=dep[fa[x]=fat]+(siz[x]=1);
for(auto t:G[x]) if(t!=fat){
dfs1(t,x); siz[x]+=siz[t];
if(siz[son[x]]<siz[t]) son[x]=t;
} return ;
}
inline void dfs2(int x,int topf){
top[x]=topf; ord[dfn[x]=++tim]=x; if(son[x]) dfs2(son[x],topf);
for(auto t:G[x]) if(!dfn[t]) dfs2(t,t);
}
struct Seg{
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
int add_tag[N<<2],col_tag[N<<2][2],Mx[N<<2][2];
int cnt[N<<2][2],cnt_tag[N<<2][2];
inline void push_cnt(int x,int c,int v){cnt_tag[x][c]+=v; cnt[x][c]+=v;}
inline void push_add(int x,int v){add_tag[x]+=v; Mx[x][0]+=v; Mx[x][1]+=v;}
inline void push_col(int x,int c,int v){col_tag[x][c]+=v; Mx[x][c]+=v;}
inline void push_down(int p){
if(add_tag[p]){
push_add(ls,add_tag[p]);
push_add(rs,add_tag[p]);
add_tag[p]=0;
}
for(int c=0;c<=1;++c) if(cnt_tag[p][c]){
push_cnt(ls,c,cnt_tag[p][c]);
push_cnt(rs,c,cnt_tag[p][c]);
cnt_tag[p][c]=0;
}
for(int c=0;c<=1;++c) if(col_tag[p][c]){
if(cnt[ls][c^1]==cnt[p][c^1]) push_col(ls,c,col_tag[p][c]);
if(cnt[rs][c^1]==cnt[p][c^1]) push_col(rs,c,col_tag[p][c]);
col_tag[p][c]=0;
}
return ;
}
inline void push_up(int p){
Mx[p][0]=Mx[p][1]=-inf;
rep(c,0,1){
if(cnt[p][c]==cnt[ls][c]) ckmax(Mx[p][c^1],Mx[ls][c^1]);
if(cnt[p][c]==cnt[rs][c]) ckmax(Mx[p][c^1],Mx[rs][c^1]);
} return ;
}
inline int query_cnt(int pos,int c,int p=1,int l=1,int r=n){
if(l==r) return cnt[p][c];
int mid=(l+r)>>1; push_down(p);
if(pos<=mid) return query_cnt(pos,c,lson);
else return query_cnt(pos,c,rson);
} // 查询一个点根链上异色点个数
inline int query_max(int st,int ed,int c,int num,int p=1,int l=1,int r=n){
if(cnt[p][c^1]>num) return -inf;
if(st<=l&&r<=ed) return Mx[p][c];
int mid=(l+r)>>1,res=0; push_down(p);
if(st<=mid) ckmax(res,query_max(st,ed,c,num,lson));
if(ed>mid) ckmax(res,query_max(st,ed,c,num,rson));
return res;
} // 查询同一个联通块的最大值
inline void cnt_add(int st,int ed,int c,int v,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return push_cnt(p,c,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) cnt_add(st,ed,c,v,lson);
if(ed>mid) cnt_add(st,ed,c,v,rson);
return push_up(p);
} // 更改异色点个数
inline void give_add(int st,int ed,int v,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return push_add(p,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) give_add(st,ed,v,lson);
if(ed>mid) give_add(st,ed,v,rson);
return push_up(p);
} // 链加,子树加
inline void col_add(int st,int ed,int c,int num,int v,int p=1,int l=1,int r=n){
if(cnt[p][c^1]>num) return ;
if(st<=l&&r<=ed) return push_col(p,c,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) col_add(st,ed,c,num,v,lson);
if(ed>mid) col_add(st,ed,c,num,v,rson);
return push_up(p);
} // 联通块加
inline void change_col(int pos,int p=1,int l=1,int r=n){
if(l==r) return swap(Mx[p][0],Mx[p][1]);
int mid=(l+r)>>1; push_down(p);
if(pos<=mid) change_col(pos,lson);
else change_col(pos,rson);
return push_up(p);
}
}T;
set<pair<int,int> > st[2][N];
inline int find(int x){
int c=col[x]^1,ans=x;
for(;x;x=fa[top[x]]){
auto t=st[c][top[x]].upper_bound(make_pair(dep[x],inf));
if(t!=st[c][top[x]].begin()){
--t;
if(t->sec==x) return ans;
else return son[t->sec];
}else ans=top[x];
} return ans;
}
signed main(){
freopen("astill.in","r",stdin); freopen("astill.out","w",stdout);
n=read(); Q=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs1(1,0); dfs2(1,1);
rep(i,1,n){
st[col[i]=read()][top[i]].insert({dep[i],i});
T.cnt_add(dfn[i],dfn[i]+siz[i]-1,col[i],1);
}
rep(i,1,n) T.give_add(dfn[i],dfn[i],read());
while(Q--){
int opt=read();
if(opt==1){
int x=read();
st[col[x]][top[x]].erase(make_pair(dep[x],x));
T.cnt_add(dfn[x],dfn[x]+siz[x]-1,col[x],-1);
col[x]^=1;
st[col[x]][top[x]].insert(make_pair(dep[x],x));
T.change_col(dfn[x]);
T.cnt_add(dfn[x],dfn[x]+siz[x]-1,col[x],1);
}else if(opt==2){
int x=find(read()),v=read();
T.col_add(dfn[x],dfn[x]+siz[x]-1,col[x],T.query_cnt(dfn[x],1^col[x]),v);
}else if(opt==3){
int x=find(read());
print(T.query_max(dfn[x],dfn[x]+siz[x]-1,col[x],T.query_cnt(dfn[x],col[x]^1)));
}else if(opt==4){
int x=read(),y=read(),v=read();
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
T.give_add(dfn[top[x]],dfn[x],v);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
T.give_add(dfn[x],dfn[y],v);
}else if(opt==5){
int x=read(),v=read();
T.give_add(dfn[x],dfn[x]+siz[x]-1,v);
}
}
return 0;
}