AtcoderABC218(D~G)题解

news/2024/7/5 5:39:26

T1 构成矩形(ABC218 D)

先预处理出所有与 x x x轴平行的边,然后暴力判断其中两条边能不能构成矩形。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL MAXN = 2005;
LL n;
struct node1 {
    LL x, y;
    bool operator<(const node1 &t) const { return x < t.x || (x == t.x && y < t.y); }
} a[MAXN];
struct node2 {
    LL xa, xb;
    LL ya, yb;
    LL len;
    bool operator<(const node2 &t) const {
        return len < t.len || (len == t.len && xa < t.xa) || (len == t.len && xa == t.xa && ya < t.ya);
    }
};
vector<node2> b;
int main() {
    scanf("%lld", &n);
    for (LL i = 1; i <= n; i++) {
        scanf("%lld%lld", &a[i].x, &a[i].y);
    }
    sort(a + 1, a + n + 1);
    for (LL i = 1; i <= n; i++) {
        for (LL j = i + 1; j <= n; j++) {
            if (a[i].y == a[j].y) {
                node2 temp;
                temp.len = a[j].x - a[i].x;
                temp.xa = a[i].x;
                temp.ya = a[i].y;
                temp.xb = a[j].x;
                temp.yb = a[j].y;
                b.push_back(temp);
            }
        }
    }
    sort(b.begin(), b.end());
    LL ans = 0;
    for (LL i = 0; i < b.size(); i++) {
        for (LL j = i + 1; j < b.size(); j++) {
            if (b[j].len != b[i].len)
                break;
            if (b[j].xa == b[i].xa)
                ans++;
        }
    }
    printf("%lld", ans);
}

T2 摧毁(ABC218 E)

把删边改为加边,问题转化为求加任意数量的边,使得最终图为连通图,最少能得到多少钱?

显然,最少的边数为 n − 1 n-1 n1,又要是连通图,就是最小生成树。

所以先标记选择的最小生成树上的边,然后在剩下的边里选择,得到最大的钱数。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL MAXN=200005;
struct node{
    LL u,v,w;
    bool operator <(const node &t)const{
        return w<t.w;
    }
}a[MAXN];
LL n,m;
LL f[MAXN];
bool vis[MAXN];
LL fi(LL x){
    if(f[x]==x)return x;
    return f[x]=fi(f[x]);
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=m;i++){
        scanf("%lld%lld%lld",&a[i].u,&a[i].v,&a[i].w);
    }
    sort(a+1,a+m+1);
    for(LL i=1;i<=n;i++){
        f[i]=i;
    }
    LL cnt=0;
    for(LL i=1;i<=m;i++){
        LL fx=fi(a[i].u),fy=fi(a[i].v);
        if(fx!=fy){
            f[fx]=f[fy];
            vis[i]=true;
            cnt++;
        }
        if(cnt==n-1)break;
    }
    LL ans=0;
    for(LL i=1;i<=m;i++){
        if(!vis[i]){
            ans=max(ans,ans+a[i].w);
        }
    }
    printf("%lld",ans);
}

T3 断边(ABC218 F)

首先想到的是暴力去做,但是这样的时间复杂度错了,因为边数最大的情况为 n 2 n^2 n2左右,所以一次 B F S BFS BFS O ( n + m ) = O ( n 2 ) O(n+m)=O(n^2) O(n+m)=O(n2),这样一来时间复杂度就来到了 O ( n 4 ) O(n^4) O(n4)

所以我们需要进行一点小优化,第一次 B F S BFS BFS时可以对未删边时的最短路上的边进行标记,如果没有删掉这些边,那答案是与第一次 B F S BFS BFS一样的。这样就可以通过了。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL MAXN=405;
const LL inf=10000000000;
LL n,m;
LL u[MAXN*MAXN],v[MAXN*MAXN];
vector<pair<LL,LL> >a[MAXN];
LL dis[MAXN];
queue<LL>q;
bool is[MAXN*MAXN];
pair<LL,LL> pre[MAXN*MAXN];
LL bfs(LL del){
    while(!q.empty())q.pop();
    q.push(1);
    for(LL i=1;i<=n;i++){
        dis[i]=inf;
    }
    dis[1]=0;
    while(!q.empty()){
        LL t=q.front();q.pop();
        for(LL i=0;i<a[t].size();i++){
            LL xx=a[t][i].first;
            LL yy=a[t][i].second;
            if(del==yy)continue;
            if(dis[xx]>dis[t]+1){
                dis[xx]=dis[t]+1;
                q.push(xx);
                if(del==0)pre[xx]={t,yy};
            }
        }
    }
    if(dis[n]>=inf)dis[n]=-1;
    return dis[n];
}
int main(){
    // freopen("C.in","r",stdin);
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=m;i++){
        scanf("%lld%lld",&u[i],&v[i]);
        a[u[i]].push_back({v[i],i});
    }
    LL ans=bfs(0),now=n;
    while(now>1){//因为无解时now会变为0,所以不能写成now!=1
        is[pre[now].second]=true;
        now=pre[now].first;
    }
    for(LL i=1;i<=m;i++){
        if(is[i])printf("%lld\n",bfs(i));
        else printf("%lld\n",ans);
    }
}

T4 树上游戏(ABC218 G)

这是一道假的博弈论题目,分析一波发现小 A A A一定会选择子树中最大的那一个,小 B B B则会选择最小的。

所以可以 d f s dfs dfs遍历一遍树,维护当前路径上的中位数,这个离散化一下,用树状数组维护,二分查找中位数就行。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL MAXN=100005;
LL n,m;
LL a[MAXN];
vector<LL>b[MAXN];
LL c[MAXN],f[MAXN];
LL s[MAXN],dep[MAXN];
LL d[MAXN];
LL lowbit(LL x){
    return x&(-x);
}
LL query(LL x){
    LL res=0;
    while(x){
        res+=s[x];
        x-=lowbit(x);
    }
    return res;
}
void add(LL x,LL k){
    while(x<=100000){
        s[x]+=k;
        x+=lowbit(x);
    }
}
void dfs(LL x,LL fa){
    dep[x]=dep[fa]+1;
    if(dep[x]&1)f[x]=0;
    else f[x]=1e9;
    bool flg=false;
    add(a[x],1);
    for(LL i=0;i<b[x].size();i++){
        LL xx=b[x][i];
        if(xx==fa)continue;
        flg=true;
        dfs(xx,x);
        if(dep[x]&1)f[x]=max(f[x],f[xx]);
        else f[x]=min(f[x],f[xx]);
    }
    if(!flg){
        LL l=1,r=m;
        while(l<r){
            LL mid=(l+r)>>1;
            if(query(mid)>=(dep[x]+1)/2)r=mid;
            else l=mid+1;
        }
        if(dep[x]&1)f[x]=c[r];
        else{
            if(query(r)>dep[x]/2)f[x]=c[r];
            else{
                LL temp=r;
                l=r+1;r=m;
                while(l<r){
                    LL mid=(l+r)>>1;
                    if(query(mid)-query(temp))r=mid;
                    else l=mid+1;
                }
                f[x]=(c[r]+c[temp])/2;
            }
        }
    }
    add(a[x],-1);
}
int main(){
    scanf("%lld",&n);
    for(LL i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        c[i]=a[i];
        d[i]=a[i];
    }
    sort(c+1,c+n+1);
    m=unique(c+1,c+n+1)-c-1;
    for(LL i=1;i<=n;i++){
        a[i]=lower_bound(c+1,c+m+1,a[i])-c;
    }
    for(LL i=1;i<n;i++){
        LL u,v;
        scanf("%lld%lld",&u,&v);
        b[u].push_back(v);
        b[v].push_back(u);
    }
    dfs(1,0);
    printf("%lld",f[1]);
}

http://lihuaxi.xjx100.cn/news/1320868.html

相关文章

因果推断Causal Inference: What If (the book)没有模型的因果推理部分章节结构

第一章 因果效应的定义 1.1 个体因果效应&#xff1a;介绍了个体因果效应的概念和定义&#xff0c;即在给定某个干预条件下&#xff0c;个体结果的变化量。1.2 平均因果效应&#xff1a;介绍了平均因果效应的概念和定义&#xff0c;即在给定某个干预条件下&#xff0c;总体结果…

消息队列 - RocketMQ

1. 名词解释和概念 NameServer&#xff1a; 是一个无状态节点&#xff0c;可集群部署&#xff0c;节点之间无任何信息同步用于服务注册和发现&#xff0c;为 MQ 集群提供服务协调与治理记录并维护 Topic 和 Broker 的信息为生产者和消费者提供 Topic 的路由信息 无状态和有状…

【C语言进阶(五)】指针进阶详解(上)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 指针进阶 1. 前言 2. 字符指针 2.…

【PCIE】协议分析之-hot-reset热复位

被上游指定热复位整个通路 当高层&#xff08;higher Layer&#xff09;指示某些通道进行热复位&#xff08;Hot Reset&#xff09;时&#xff0c;以下操作将被执行&#xff1a; 所有在配置的链路中的通道都会发送带有热复位位&#xff08;Hot Reset bit&#xff09;和配置的…

第三章 数据链路层【计算机网络】

第三章 数据链路层【计算机网络】 前言推荐第三章 数据链路层3.1 数据链路层的几个共同问题3.1.1 数据链路和帧3.1.2 三个基本问题 3.2点对点协议PPP3.2.1 PPP协议的特点3.2.2 PPP协议的帧格式3.2.3 PPP协议的工作状态 3.3 使用广播信道的数据链路层3.3.1 局域网的数据链路层3.…

spark动态资源调度中的shuffle service的数据清理

External Shuffle Service的问题 在 spark2 中&#xff0c;如果想要使用动态资源调度&#xff0c;external shuffle service外部独立的shuffle服务是必须条件&#xff0c;因为 spark 需要确保回收 executor 时不会删除生成的 shuffle 数据&#xff0c;外部的 shuffle 服务可以…

STL好难(5):stack的使用

目录 1.stack的介绍和使用&#xff1a; 2.stack的使用 3.有关stack的练习题&#xff1a; &#x1f349;最小栈 &#x1f349;栈的压入、弹出序列 4.stack的模拟实现&#xff1a; 1.stack的介绍和使用&#xff1a; 点击查看stack的文档介绍 1. stack是一种容器适配器&#…

Oracle之Scott用户

Oracle增删改查&#xff0c;事务与序列 前言 1、解锁scott用户 2、雇员表&#xff08;emp&#xff09; 3、部门表&#xff08;dept&#xff09; 4、工资等级表&#xff08;salgrade&#xff09;了解 5、奖金表&#xff08;bonus&#xff09;了解 1、解锁scott用户 --解锁scot…