2024.1.24 训练赛

A

一个比较经典的加权并查集,或者dfs也可以,没啥区别,主要是我忘了怎么写dfs了,第一时间想到的就是并查集,需要注意的事要路径压缩,居然忘了。。

核心代码可能就是找父亲和计算到父亲的距离了,其他真没啥了

 

#include<bits/stdc++.h>

const int MAXN = 2e5 + 10;
using namespace std;
typedef long long LL;
typedef pair<int, LL> P;

int T;
int n, m;
int a, b;
LL d;
struct node
{
    int fa;
    LL x;
};
node k[MAXN];

P findfa(int x)
{
    if(x != k[x].fa)
    {
        P res = findfa(k[x].fa);
        k[x].x += res.second;
        k[x].fa = res.first;
    }
    return {k[x].fa, k[x].x};
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>> T;
    while(T--)
    {
        cin>> n >> m;
        int flag = 1;
        for(int i = 1;i <= n;i++) k[i].fa = i, k[i].x = 0;
        for(int i = 1;i <= m;i++)
        {
            cin >> a >> b >> d;
            if(!flag) continue;
            if(d < 0) d = -d, swap(a, b);
            P f1 = findfa(a), f2 = findfa(b);
            if(f1.first == f2.first)
            {
                if(f2.second - f1.second == d) continue;
                else flag = 0;
            }
            else 
            {
                k[f2.first].fa = f1.first;
                k[f2.first].x += d + f1.second - f2.second;                    
            }
        }
//        for(int i = 1;i <= n;i++) cout<<i<<" "<<k[i].fa<<" "<<k[i].x<<'\n';
        if(flag) cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}
View Code

还有dfs写法,写放在这

我说这道题这么眼熟,以前写过


B

还好是相邻的交换,如果改成任意位置都可以交换就是另一种难度和做法了。

对于这道题很简单,其实就是求逆序对之和

边输入边处理就完事了,对于输入的每一个数,求在前面,出现的比他大的数之和,然后求出这些数的个数,乘以他自己就是要他到达正确位置需要花费的时间,用线段树和树状数组都可以做,但很明显树状数组更简单,但很明显我忘了还有树状数组这回事了。

问题:

1.人家只说奶牛个数和暴躁程度的范围相同,可从没说过每个奶牛的暴躁程度都不一样

2.四倍的空间居然爆了????奇怪。以后建议开八倍

 

C

这道题也蛮简单,只要二分可以连续摧毁的机器最大个数 mid 就好了

然后对一个连续的区间 l , l + mid - 1,判断这个区间内,每种细节的最大值之和是不是小于等于所给的 F 就好了

问题:

没有问题!一遍过

线段树越写越熟练了

#include<bits/stdc++.h>

const int MAXN = 1e5 + 10;
using namespace std;
typedef long long LL;

int n, m, k;
struct node
{
    int l, r;
    int a[6];
}t[MAXN << 3];

int p[MAXN][6];
LL ans[6], pr[6];
int flag;

void build(int rt, int l, int r)
{
    if(l == r)
    {
        t[rt].l = t[rt].r = l;
        for(int i = 1;i <= m;i++) t[rt].a[i] = p[l][i];
        return ;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    t[rt].l = l;
    t[rt].r = r;
    for(int i = 1;i <= m;i++)
        t[rt].a[i] = max(t[rt<<1].a[i], t[rt<<1|1].a[i]);
    return ;
}

void query(int rt, int l, int r)
{
    if(t[rt].l > r || t[rt].r < l) return ;
    if(t[rt].l >= l && t[rt].r <= r) 
    {
        for(int i = 1;i <= m;i++)
            ans[i] = max(ans[i], (LL)t[rt].a[i]);
        return;
    }
    int mid = t[rt].l + t[rt].r >> 1;
    query(rt << 1, l, r);
    query(rt << 1 | 1, l, r);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>> n >> m >> k;
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            cin>> p[i][j];
    build(1, 1, n);
//    for(int i = 1;i <= 6;i++){
//        cout<< i << " " << t[i].l << " " << t[i].r<< " :";
//        for(int j = 1;j <= m;j++) cout<< t[i].a[j] << " \n"[j==m];    
//    }
    int l = 0,r = n;
    LL res = 0;
    while(l <= r)
    {
        int mid = l + r >> 1;
        flag = 0;
        for(int i = 1;i <= n - mid + 1;i++)
        {
            res = 0;
            query(1, i, i + mid - 1);
//            cout<< i << " " << i + mid - 1 << " :";
            for(int j = 1;j <= m;j++) res += ans[j];
            if(res <= k)
            {
                flag = 1; 
                for(int j = 1;j <= m;j++) pr[j] = ans[j];
                break;
            }
            for(int j = 1;j <= m;j++) ans[j] = 0;
        }
        if(flag) l = mid + 1;
        else r = mid - 1;
    }
//    cout<< l <<" "<<r<<'\n';
    for(int i = 1;i <= m;i++) cout<< pr[i] << " \n"[i==m];
    return 0;
}
View Code

 

D

没啥难的,只需要知道从后往前找,让每次修改的范围不断变大就可以了。就是打印输出我感觉有点绕

我是先从小到大排序,然后用两个区间卡住还没打印的区域,如果是要求升序,那就从 r 开始数,如果降序就从 l, 然后更新 l 或者 r 就好了。赛时怎么没想到。

#include<bits/stdc++.h>

const int MAXN = 2e5 + 10;
using namespace std;

int n, m;
int op, r;
int k[MAXN];
int kk[MAXN];
struct node
{
    int op;
    int r;
};
pair <int, int> ord[MAXN];
int cnt2;
node q[MAXN], p[MAXN];
int cnt;

bool cmp1(int a, int b){return a < b;}
bool cmp2(int a, int b){return a > b;}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>> n >> m;
    for(int i = 1;i <= n;i++) cin>> k[i], kk[i] = k[i];
    for(int i = 1;i <= m;i++) cin>> p[i].op >> p[i].r;
    
    for(int i = m;i;i--)
    {
        if(p[i].r > q[cnt].r) 
            q[++cnt] = p[i];
    }
    sort(k + 1, k + q[cnt].r + 1, cmp1);
    ord[++cnt2].first = q[cnt].r + 1;
    ord[cnt2].second = n;
    q[0].r = 0;
    int l = 1, r = q[cnt].r;
//    for(int i = cnt;i;i--) cout<< q[i].op << " " << q[i].r << '\n';
    for(int i = cnt;i;i--)
    {
        int len = q[i].r - q[i - 1].r;
        if(q[i].op == 1) 
            ord[++cnt2].first = r - len + 1, ord[cnt2].second = r, r -= len;
        else 
            ord[++cnt2].first = l + len - 1, ord[cnt2].second = l, l += len;
            
    }
    for(int i = cnt2;i;i--)
    {
        int a = ord[i].first, b = ord[i].second;
        if(a > n || b > n) continue;
//        cout << a << " " << b << ":";
        if(a < b)
            for(int j = a;j <= b;j++)
                cout<<k[j]<<" ";
        else 
            for(int j = a;j >= b;j--)
                cout<<k[j]<<' ';
//        cout << '\n';
    }
    return 0;
}
View Code

 

posted @ 2024-01-24 00:10  是谁不可理喻  阅读(12)  评论(0)    收藏  举报