【学习笔记】[省选联考 2023] 填数游戏

这篇具有很好参考价值的文章主要介绍了【学习笔记】[省选联考 2023] 填数游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我不好说,因为考场上我想成二分图然后就gg了

这题不难,真的不难。

∣ T i ∣ ≤ 2 |T_i|\le 2 Ti2这个性质一看就非常亲切啊,可以看成一条 a i a_i ai b i b_i bi的连边,不妨将问题做一些泛化,将 ∣ T i ∣ = 1 |T_i|=1 Ti=1看成连向 a i a_i ai的自环。

那么对于一个连通块显然边的数目不超过点的数目,让我们先讨论一些比较简单的情形。

如果基环树且基环为自环,那么选择方式唯一,简单算一下即可。

如果基环树且基环不为自环,那么基环外选择方式唯一,基环内有两种方式,简单贪心一下应该不难得出答案。

如果为树,假设 { a i } \{a_i\} {ai}已经确定了,不妨看成是以 u u u为根并且完成定向的一颗有根树, Bob \text{Bob} Bob可以将 v v v到根节点的路径上的边反向,那么相当于每个点存了一个答案,初始所有点答案都为 0 0 0 Bob \text{Bob} Bob会选择答案最小的那个点。然后 Alice \text{Alice} Alice依次加入每条边,对于没有别固定的边 ( u , v ) (u,v) (u,v),设 u u u v v v的父亲,如果选 v v v相当于 v v v子树外的点答案 + 1 +1 +1,如果选 u u u相当于 v v v子树内的点答案 + 1 +1 +1(称为不动点),如果有两个点 u , v u,v u,v都是翻转点,那么显然 u , v u,v u,v满足祖先关系(否则不优),而显然选深度小的点作为不动点更优,那么就做完了。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

总之是非常套路的题,但是不知道为啥考场上没想出来。

总之就是非常难写,今年省选代码量确实有一点点大文章来源地址https://www.toymoban.com/news/detail-407698.html

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define db double
#define fi first
#define se second
using namespace std;
const int N=1e6+5;
int T,n,m,fa[N],sz1[N],sz2[N],a[N][2],b[N][2];
int rt,re,pre[N],prepos[N],visit[N],task,res,dfn[N],num,home[N],cntnode;
int head[N*2],nxt[N*2],to[N*2],pos[N*2],tot;
int posedge;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct node{
    int dat,min;
}t[N<<2];
void Add(int p,int x){
    t[p].min+=x,t[p].dat+=x;
}
void pushup(int p){
    t[p].min=min(t[p<<1].min,t[p<<1|1].min);
}
void pushdown(int p){
    if(t[p].dat){
        Add(p<<1,t[p].dat),Add(p<<1|1,t[p].dat);
        t[p].dat=0;
    }
}
void upd(int p,int l,int r,int ql,int qr,int x){
    if(ql<=l&&r<=qr){
        Add(p,x);
        return;
    }
    int mid=l+r>>1;pushdown(p);
    if(ql<=mid)upd(p<<1,l,mid,ql,qr,x);
    if(mid<qr)upd(p<<1|1,mid+1,r,ql,qr,x);
    pushup(p);
}
int qry(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return t[p].min;
    int mid=l+r>>1;pushdown(p);
    if(qr<=mid)return qry(p<<1,l,mid,ql,qr);
    if(mid<ql)return qry(p<<1|1,mid+1,r,ql,qr);
    return min(qry(p<<1,l,mid,ql,qr),qry(p<<1|1,mid+1,r,ql,qr));
}
void add(int x,int y,int z){
    to[++tot]=y,pos[tot]=z,nxt[tot]=head[x],head[x]=tot;
    to[++tot]=x,pos[tot]=z,nxt[tot]=head[y],head[y]=tot;
}
void unionset(int x,int y){
    int u=find(x),v=find(y);
    if(u!=v)fa[u]=v,sz1[v]+=sz1[u]+1,sz2[v]+=sz2[u];
    else sz1[v]++;
}
int calc(int pos,int v){
    assert(v);
    return a[pos][0]==v||a[pos][1]==v;
}
int X,Y,Z;
int check(int pos){
    return a[pos][0]==b[pos][0]&&a[pos][1]==b[pos][1]||a[pos][0]==b[pos][1]&&a[pos][1]==b[pos][0];
}
//fixed
void findroot(int u,int topf){
    visit[u]=task;
    for(int k=head[u];k;k=nxt[k]){
        if(k!=(topf^1)){
            int v=to[k];
            if(visit[v]!=task)findroot(v,k);
            else {
                rt=u;
                if(u==v)posedge=pos[k];
            }
        }
    }
}
//fixed
void dfs(int u,int topf){
    visit[u]=task;
    for(int k=head[u];k;k=nxt[k]){
        int v=to[k];
        if(k!=(topf^1)){
            if(visit[v]!=task){
                pre[v]=u,prepos[v]=pos[k],dfs(v,k);
                res+=calc(pos[k],v);
            }
            else if(u!=rt){
                assert(!re);
                re=u;
                if(check(pos[k])){
                    Z++;
                }
                else {
                    if(calc(pos[k],rt))X++;
                    else if(calc(pos[k],re))Y++;
                }
            }
        }
    }
}
int solve1(int u){
    rt=u,re=0,task++;
    X=0,Y=0,Z=0,res=0,posedge=0;
    findroot(rt,0);
    if(posedge)res+=calc(posedge,rt);
    task++;
    dfs(rt,0);
    if(!re)return res;
    assert(rt!=re);
    while(re!=rt){
        int tmp=prepos[re];
        res-=calc(tmp,re);
        if(check(tmp)){
            Z++;
        }
        else{
            if(calc(tmp,re))X++;
            else if(calc(tmp,pre[re]))Y++;
        }
        re=pre[re];
    }
    if(X>Y)swap(X,Y);
    if(X+Z<=Y)return X+Z+res;
    return (X+Y+Z)/2+res;
}
void modify(int u,int state,int f){
    if(state==0){
        upd(1,1,m,dfn[u],dfn[u]+home[u]-1,f);
    }
    else{
        upd(1,1,m,dfn[u],dfn[u]+home[u]-1,-f);
        upd(1,1,m,1,cntnode,f);
    }
}
void dfs1(int u,int topf){
    dfn[u]=++num,home[u]=1,cntnode++;
    for(int k=head[u];k;k=nxt[k]){
        int v=to[k];
        if(v!=topf){
            dfs1(v,u),home[u]+=home[v];
        }
    }
}
void dfs2(int u,int topf,int f){
    for(int k=head[u];k;k=nxt[k]){
        int v=to[k];
        if(v!=topf){
            if(check(pos[k])){
                modify(v,1,f);
            }
            else if(calc(pos[k],v)){
                modify(v,1,f);
            }
            else if(calc(pos[k],u)){
                modify(v,0,f);
            }
            dfs2(v,u,f);
        }
    }
}
void dfs3(int u,int topf){
    res=max(res,qry(1,1,m,1,cntnode));
    for(int k=head[u];k;k=nxt[k]){
        int v=to[k];
        if(v!=topf){
            if(check(pos[k])){
                modify(v,1,-1);
                modify(v,0,1);
            }
            dfs3(v,u);
            if(check(pos[k])){
                modify(v,1,1);
                modify(v,0,-1);
            }
        }
    }
}
int solve2(int u){
    num=0,cntnode=0,dfs1(u,0);
    assert(cntnode==sz2[find(u)]);
    res=0;
    dfs2(u,0,1),dfs3(u,0),dfs2(u,0,-1);
    assert(t[1].min==0);
    return res;
}
int solve(){
    int tot=0;
    for(int i=1;i<=m;i++){
        if(find(i)==i){
            if(sz1[i]>sz2[i]){
                return -1;
            }
            if(sz1[i]==sz2[i])tot+=solve1(i);
            else tot+=solve2(i);
        }
    }
    return tot;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n>>m;tot=1;for(int i=1;i<=m;i++)head[i]=0;
        for(int i=1;i<=m;i++)fa[i]=i,sz1[i]=0,sz2[i]=1;
        for(int i=1;i<=n;i++)a[i][0]=a[i][1]=b[i][0]=b[i][1]=0;
        for(int i=1;i<=n;i++){
            int k;cin>>k;
            while(k--)cin>>a[i][k];
        }
        for(int i=1;i<=n;i++){
            int k;cin>>k;
            if(k==2){
                while(k--)cin>>b[i][k];
                unionset(b[i][0],b[i][1]);
                add(b[i][0],b[i][1],i);
            }
            else{
                while(k--)cin>>b[i][k];
                unionset(b[i][0],b[i][0]);
                add(b[i][0],b[i][0],i);
            }
        }
        cout<<solve()<<"\n";
    }
}

到了这里,关于【学习笔记】[省选联考 2023] 填数游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 程序员工作久了,都不会好好说人话了...互联网人的....黑话

    原来工作也是会被腌入味的 前段时间有位博主吐槽 工作太久都不会说人话了 这张口的互联网味儿 瞬间梦回自己的工位 而评论区的网友们表示 这不就是”世另我“吗 一场关于互联网黑话的\\\"掰头\\\" 就此开始了... 维护厨房 (厨房秒变公司) 新增小孩 update菜单 民宿排期 店员交

    2023年04月19日
    浏览(11)
  • 原型模式 Prototype Pattern 《游戏编程模式》学习笔记

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 假设我现在要做一款游戏,这个游戏里有许多不同种类的怪物,鬼魂,恶魔和巫师。这些怪物通过“生产者”进入这片区域,每种敌人有不同的生产者。 假设每种怪物都有不同的类,同时他们都继承怪

    2024年02月12日
    浏览(13)
  • 《游戏编程模式》学习笔记(十二)子类沙箱 Subclass Sandbox

    基类定义抽象的沙箱方法和几个提供的操作。 将操作标为protected,表明它们只为子类所使用。 每个推导出的沙箱子类用提供的操作实现了沙箱函数。 假设我们在做一个超级英雄的游戏,我们现在要实现一些超能力。我们计划创建一个Superpower基类。然后由它派生出各种超级能

    2024年02月09日
    浏览(9)
  • 享元模式 Flyweight Pattern 《游戏编程模式》学习笔记

    如果我们要存储一个树一样的数据结构,直觉来说我们会这么写 但是实际上我们会发现,哪怕森林里有千千万万的树,它们大多数长得一模一样。 它们使用了相同的网格和纹理。 这意味着这些树的实例的大部分字段是一样的。 那么我们就可以将树共有的数据拿出来分离到另

    2024年02月13日
    浏览(15)
  • 命令模式 Command Pattern 《游戏设计模式》学习笔记

    对于一般的按键输入,我们通常这么做,直接if按了什么键,就执行相应的操作 在这里我们是将用户的输入和程序行为硬编码在一起,这是我们很自然就想到的最快的做法。 但是如果这是一个大型游戏,往往我们需要实现一个按键配置的功能(话说2077直到上线都没有实现这

    2024年02月14日
    浏览(17)
  • 《游戏编程模式》学习笔记(七)状态模式 State Pattern

    允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。 在书的示例里要求你写一个人物控制器,实现跳跃功能 直觉上来说,我们代码会这么写: 可是这么写不对,因为人物本身应该只能跳一次,这样写的话人物就可以无限按B实现跳跃了。我们加一个

    2024年02月11日
    浏览(15)
  • 2023清华大学go学习笔记

    go(又称Golang) 应用领域: go服务器 go分布式/云计算 区块链工程师 360开源的日志搜索系统 qihoo360/poseidon 开发团队: 罗伯特·格瑞史莫(Robert Griesemer),罗勃派克(Rob) Pike)及肯·汤曾逊(Ken Thompson)于2007年9月开始设计Go,稍后lan LanceTaylor、Russ Cox0入项目. Rcoect CicepeeneR9D Pae Go语言发展

    2024年02月05日
    浏览(17)
  • 《游戏编程模式》学习笔记(六)单例模式 Singleton Pattern

    保证一个类只有一个实例,并且提供了访问该实例的全局访问点。 定义这种东西一般都是不说人话的,要想要理解这句话的意思,我们得把它揉开了才能搞明白。 我们先看前半句 “保证一个类只有一个实例”,单例一般使用类来实现,也就是说,这个单例类,其有且只能有

    2024年02月12日
    浏览(14)
  • 【流畅的Python学习笔记】2023.4.29

    此栏目记录我学习《流畅的Python》一书的学习笔记,这是一个自用笔记,所以写的比较随意,随缘更新 collections.abc 模块中有 Mapping 和 MutableMapping 这两个抽象基类,它们的作用是为dict 和其他类似的类型定义形式接口 运行结果: True 通过isinstance 的结果能够判断出字典是广义

    2024年02月01日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包