【考试总结】2022-03-25

异或矩阵

使用 库默尔定理 发现,如果 yxk1 那么 (1,y) 将向 (k,x) 造成贡献

考虑当 k=2x 时转移只有两个地方是子集,那么分 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;
}

点集 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 来实现找到根链上第一个异色点再跳儿子即可

将线段树上某个区间管辖点视作其所有点的 LCA,维护如下信息:

  • cnt[0/1] 表示两个颜色点数

  • Mx[0/1] 表示两种颜色联通块中的最值

  • cnt_tag[0/1],col_tag[0/1],tag 分别表示三种懒标记:点数修改,同色权值加,子树/链 加

在进行区间修改的时候先查询联通块最浅点的 cnt 信息,再对其进行子树加即可,注意 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;
}

posted @   没学完四大礼包不改名  阅读(115)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示