【考试总结】2022-03-18

无向图

问题是 S 形成的线性空间维度数量,使用可删除线性基来实现即可

一种做法是线段树分治

Code Display
int m,Q;
struct Linear_Basis{
    int b[40]; Linear_Basis(){memset(b,0,sizeof(b));}
    inline void insert(int x){
        for(int i=m;i>=1;--i) if(x>>(i-1)&1){
            if(!b[i]) return b[i]=x,void();
            else x^=b[i];
        } return ;
    }
    inline int solve(){
        int cnt=0;
        for(int i=1;i<=m;++i){
            cnt+=(bool)b[i];
        } return 1ll<<cnt;
    }
};
const int N=2e5+10;
vector<int> ele[N<<2];
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
inline void upd(int st,int ed,int v,int p=1,int l=1,int r=Q){
    if(st<=l&&r<=ed)return ele[p].push_back(v),void();
    int mid=(l+r)>>1;
    if(st<=mid) upd(st,ed,v,lson); if(ed>mid) upd(st,ed,v,rson);
    return ;
}
inline void solve(int p,int l,int r,Linear_Basis now){
    for(auto v:ele[p]) now.insert(v);
    if(l==r) return print(now.solve());
    int mid=(l+r)>>1;
    solve(lson,now); solve(rson,now);
    return ;
}
#undef lson
#undef rson
map<int,int> mp;
signed main(){
    freopen("xor.in","r",stdin); freopen("xor.out","w",stdout);
    m=read(); Q=read();
    for(int i=1;i<=Q;++i){
        int opt=read();
        int x=read();
        if(opt==1) mp[x]=i;
        else upd(mp[x],i-1,x),mp.erase(x);
    }
    for(auto t:mp) upd(t.sec,Q,t.fir);
    Linear_Basis tmp;
    solve(1,1,Q,tmp);
    return 0;
}

加与乘

考虑到如果 A 最后一次操作那么一定赢,否则如果 B 最后一次操作的时候没有奇数那么也会输

所以问题可以表达作 A 最少使用多少次操作可以让序列里面没有 1

注意在删掉两个奇数这个过程中一定 B 一定能找得到偶数把它删掉,如果全是奇数 A 删掉一个逼迫 B 删奇数和直接删两个效率一样

Code Display
signed main(){
    freopen("game.in","r",stdin); freopen("game.out","w",stdout);
    int T=read(); while(T--){
        int n,opt;
        n=read(); opt=read();
        vector<int> vec(n);
        rep(i,0,n-1) vec[i]=read()&1;
        if((n&1)==opt) cout<<"A"<<endl;
        else{
            int conse=0,tim=0;
            for(int i=0;i<n;++i){
                if(!vec[i]) tim+=(conse+1)/2,conse=0;
                else conse++;
            }
            tim+=(conse+1)/2;
            if(tim>(n-1)/2) puts("B");
            else puts("A");
        }
    }   
    return 0;
}

数颜色

考虑前两天做的经典容斥:一条链上点数 边数 =1,所以将不经过父边的 LCA 拿出来

使用主席树计算前缀每个点被覆盖次数,配合以二分可以算出来这个 LCA 作为联通块深度最小点的区间,相同 LCA 找最后一个即可

得到贡献区间之后使用 Fenwick Tree 即可

Code Display
const int N=1e5+10;
int n,m,Q,x[N],y[N];
vector<int> G[N];
int fa[N],son[N],dep[N],siz[N],top[N],dfn[N],tim;
inline void dfs1(int x,int y){
    dep[x]=dep[fa[x]=y]+(siz[x]=1);
    for(int t:G[x]) if(t!=y){
        dfs1(t,x); siz[x]+=siz[t];
        if(siz[t]>siz[son[x]]) son[x]=t;
    } return ;
}
inline void dfs2(int x,int topf){
    top[x]=topf; dfn[x]=++tim; if(son[x]) dfs2(son[x],topf);
    for(auto t:G[x]) if(!dfn[t]) dfs2(t,t);
    return ;
}
inline int get_lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
struct Fenwick{
    int c[N];
    inline int query(int x){int res=0; for(;x;x-=x&(-x)) res+=c[x]; return res;}
    inline void insert(int x,int v){for(;x<=m;x+=x&(-x)) c[x]+=v; return ;}
}T;
int ans[N];
vector<pair<int,int> >qu[N];
vector<tuple<int,int,int> >vals[N];
const int M=N*300;
int Tim,tot,rt[N],ls[M],rs[M],tag[M];
inline void upd(int &p,int pre,int l,int r,int st,int ed){    
    if(p<=Tim) p=++tot,ls[p]=ls[pre],rs[p]=rs[pre],tag[p]=tag[pre];
    if(st<=l&&r<=ed) return tag[p]++,void();
    int mid=(l+r)>>1;
    if(st<=mid) upd(ls[p],ls[pre],l,mid,st,ed);
    if(ed>mid) upd(rs[p],rs[pre],mid+1,r,st,ed);
    return ;
}
inline int query(int p,int l,int r,int pos){
    if(!p) return 0;
    if(l==r) return tag[p]; int mid=(l+r)>>1;
    if(pos<=mid) return query(ls[p],l,mid,pos)+tag[p];
    else return query(rs[p],mid+1,r,pos)+tag[p];
}
int lca[N];
inline void push_path(int id,int x,int y){
    rt[id]=rt[id-1]; Tim=tot;
    lca[id]=get_lca(x,y);
    while(top[x]!=top[lca[id]]){
        upd(rt[id],rt[id],1,n,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    while(top[y]!=top[lca[id]]){
        upd(rt[id],rt[id],1,n,dfn[top[y]],dfn[y]);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    if(x!=y) upd(rt[id],rt[id],1,n,dfn[x]+1,dfn[y]);
    return ;
}
int pre[N],nxt[N],lst[N];
signed main(){
    freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
    n=read(); m=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);
    for(int i=1;i<=m;++i){
        x[i]=read(),y[i]=read();
        push_path(i,x[i],y[i]);
    }
    for(int i=1;i<=m;++i){
        nxt[lst[lca[i]]]=i;
        pre[i]=lst[lca[i]];
        lst[lca[i]]=i;
    }
    for(int i=1;i<=n;++i) if(lst[i]) nxt[lst[i]]=m+1;
    for(int i=1;i<=m;++i){
        int lef=0,rig=i-1,ans=i;
        while(lef<=rig){
            int mid=(lef+rig)>>1;
            if(query(rt[mid],1,n,dfn[lca[i]])==query(rt[i],1,n,dfn[lca[i]])) rig=mid-1,ans=mid;
            else lef=mid+1;
        }
        int pos=ans+1;
        vals[i].emplace_back(pos,i,1);
        lef=i+1,rig=m; ans=m+1;
        while(lef<=rig){
            int mid=(lef+rig)>>1;
            if(query(rt[mid],1,n,dfn[lca[i]])==query(rt[i],1,n,dfn[lca[i]])) lef=mid+1;
            else rig=mid-1,ans=mid;
        }
        vals[min(nxt[i],ans)].emplace_back(pos,i,-1);
    }
    for(int i=1;i<=Q;++i){
        int l=read(),r=read();
        qu[r].emplace_back(l,i);
    }
    for(int i=1;i<=m;++i){
        for(auto t:vals[i]){
            int a,b,c; tie(a,b,c)=t;
            T.insert(a,c);
            T.insert(b+1,-c);
        }
        for(auto q:qu[i]) ans[q.sec]=T.query(q.fir);
    }
    for(int i=1;i<=Q;++i) print(ans[i]);
    return 0;
}

感觉这套题在联赛前考和在现在考多数同学的得分并不会有什么不同

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