Codeforces Round #826 (Div. 3) D E F

Codeforces Round #826 (Div. 3)

D. Masha and a Beautiful Tree (递归)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题意:
对于每个样例,输入一个m,之后输入一个长度为m的排列(m好像保证一定是2^i),输入的排列是一颗完全二叉树的叶子结点。你可以进行一种操作:操作每一个非叶子节点,交换他的两个左右儿子(左右子树也会跟着交换)。问你进行多少次操作可以使这个排列p满足 p i = i p_i = i pi=i,输出最小的操作次数,无法操作输出-1。
分析:
二叉树是递归定义的。
可以考虑把这棵树看成一颗线段树,维护区间最大值(或者最小值),这样每个结点的值就都有了,我们假设叶子结点所在那层为第0层,其父亲结点在第1层,。。。,根节点在最高层,那么对于第i层的两个兄弟结点 p 1 , p 2 p_1, p_2 p1,p2,它们必须满足 ∣ p 1 − p 2 ∣ = 2 i |p_1 - p_2| = 2^i p1p2=2i,否则答案将是-1。对于操作,如果左儿子大于右儿子,则需要操作其父节点。二叉树是递归定义的,递归跑一遍即可(dfs)。
AC代码:

#include <bits/stdc++.h>

using namespace std;

int t, n;
int ar[300000];
bool flag;
int ans;
int bas[30];

struct node
{
    int l, r, mi;
    int dep;
}tree[1100050];

void init()
{
    bas[0] = 1;
    for(int i = 1; i <= 30; ++i) bas[i] = bas[i - 1] * 2;
}

void pushup(int p)
{
    if(abs(tree[p<<1].mi - tree[p<<1|1].mi) != bas[tree[p<<1].dep]) flag = true;
    tree[p].mi = min(tree[p<<1].mi, tree[p<<1|1].mi);
}

void build(int p, int l, int r)
{
    tree[p].l = l, tree[p].r = r;

    if(l == r)
    {
        tree[p].mi = ar[l];
        tree[p].dep = 0;
        return ;
    }

    int mid = (l + r) >> 1;

    build(p<<1, l, mid);
    build(p<<1|1, mid + 1, r);
    tree[p].dep = tree[p<<1].dep + 1;

    pushup(p);
}

void dfs(int p)
{
    if(tree[p].l == tree[p].r) return;

    if(tree[p<<1].mi > tree[p<<1|1].mi) ++ans;
    dfs(p<<1);
    dfs(p<<1|1);
}

int main()
{
    scanf("%d", &t);

    init();

    while(t--)
    {
        scanf("%d", &n);

        for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);

        flag = false;
        ans = 0;

        build(1, 1, n);
        if(flag)
        {
            printf("-1\n");
            continue;
        }

        dfs(1);

        printf("%d\n", ans);
    }
    return 0;
}

E. Sending a Sequence Over the Network(递推/简单dp)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题意:
对于一个长度为m的数组ar,可以将它分割成很多段( l i , r i l_i,r_i li,ri),任意一段没有交集,且所有段合起来是(1,n)之后在某一段的左边或者右边添加一个数字k,k为这一段的长度,由此获得数组br。
对于每一个样例,输入一个n,代表数组br的长度,之后输入数组br,问是否存在一个数组ar,经过操作后能够变成数组br。
分析:
定义一个bool类型数组vis,vis[i]表示数组br中,位置i能否作为一段的终止, O ( n ) O(n) O(n)递推转移一下即可(对于每个点,枚举他作为区间最左或者最右的情况),注意不要re,答案就是vis[n]
AC代码:

#include <bits/stdc++.h>

using namespace std;

bool vis[200050];
int t, n;
int ar[200050];

int main()
{
    scanf("%d", &t);

    while(t--)
    {
        scanf("%d", &n);

        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &ar[i]);
            vis[i] = false;
        }

        vis[0] = true;
        for(int i = 1; i <= n; ++i)
        {
            if(i - ar[i] - 1 >= 0) vis[i] |= vis[i - ar[i] - 1];

            if(i + ar[i] <= n) vis[i + ar[i]] |= vis[i - 1];
        }

        if(vis[n]) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

F. Multi-Colored Segments (排序+维护前缀最大值和前缀次大值)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题意:
在一个数轴上有n个线段,对于每段线段,其左端点和右端点一定是整数,每个线段有一个颜色,两个线段的距离是从两个线段中分别选取两个点求两点间距离,这个距离的最小值为两个线段的距离(相交距离为0,不相交左面线段选右端点,右面线段选左端点)。对于每段线段,求离它最近的一个和它颜色不同的线段的距离。
分析:
对于线段 i i i ( l i , r i , c i ) (l_i,r_i,c_i) (li,ri,ci),离它最近的且和它颜色不同的线段的距离可以分为两部分,位于 r i r_i ri左侧的线段(如果线段 j j j满足 l j < = r i l_j<=r_i lj<=ri,则认为线段 j j j位于其左侧)且于线段 i i i颜色不同的线段距线段 i i i的距离 s 1 s_1 s1,位于 l i l_i li右侧的且于线段 i i i颜色不同的线段距线段 i i i的距离为 s 2 s_2 s2,则 a n s i = m i n ( s 1 , s 2 ) ans_i = min(s_1, s_2) ansi=min(s1,s2).
对于某个线段 i i i,求其 s 1 s_1 s1,维护满足条件的线段 j j j r j r_j rj的最大值和次大值(最大值和次大值对应的线段颜色应当不同,即一种颜色只记一个最大值),若线段 i i i与最大值对应线段颜色不同,则 s 1 s_1 s1由最大值决定(假设最大值是 m x mx mx,则 s 1 = m a x ( 0 , m x − r i ) s_1 = max(0,mx-r_i) s1=max(0,mxri)),否则由次大值决定。
由此,可通过排序+遍历取得,对于求 s i s_i si应将线段 i i i所在数组按照 r i r_i ri从小到大排序,线段 j j j所在的数组按照 l j l_j lj从小到大排序,之后遍历即可。而对于 s 2 s_2 s2,可以将线段的 l ∗ = − 1 , r ∗ = − 1 l *=-1,r *=-1 l=1,r=1,之后 s w a p ( l , r ) swap(l,r) swap(l,r),再按照上面求 s 1 s_1 s1的方法计算一遍即可得 s 2 s_2 s2
AC代码:

#include <bits/stdc++.h>

using namespace std;

const int inf = 0x3f3f3f3f;
int t, n;
int mxl[200050], mxr[200050];//两次遍历过程中颜色i对应线段的最大值
struct node
{
    int l, r, c;
    int id;
} ar[200050], br[200050];
int mx_l, mxl_color, mxxl, mxxl_color;//第一次遍历过程中的最大值,最大值对应的颜色,次大值
int mx_r, mxr_color, mxxr, mxxr_color;
int ans[200050];
bool flag1, flag2;//是否有最大值,次大值

bool cmp1(node a, node b)
{
    return a.r < b.r;
}

bool cmp2(node a, node b)
{
    return a.l < b.l;
}

void init()
{
    mx_l = mxl_color = mxxl = mxr_color = 0;
    mx_r = mxxr = -inf;
    flag1 = flag2 = false;
    for(int i = 1; i <= n; ++i)
    {
        mxl[i] = 0;
        ans[i] = inf;
        mxr[i] = -inf;
    }
}

void work_l()
{
    int beg = 0, color = 0;
    for(int i = 1; i <= n; ++i)
    {
        //cout << i << '\n';
        for(int j = beg + 1; br[j].l <= ar[i].r && j <= n; ++j)
        {
            //cout << j << '\n';
            color = br[j].c;
            if(br[j].r > mxl[color])
            {
                mxl[color] = br[j].r;
                if(mxl[color] > mx_l)
                {
                    if(mxl_color == color) mx_l = mxl[color];
                    else
                    {
                        mxxl = mx_l;
                        mx_l = mxl[color];
                        mxl_color = color;
                        flag1 = true;
                        if(mxxl != 0) flag2 = true;
                    }
                }
                else if(mxl[color] > mxxl && color != mxl_color)
                {
                    mxxl = mxl[color];
                    flag2 = true;
                }
            }
            beg = j;
        }

        //cout << i << ' ' << beg << '\n';

        //cout << i << ' ' << flag1 << ' ' << flag2 << '\n';
        if(ar[i].c != mxl_color && flag1) ans[ar[i].id] = min(ans[ar[i].id], max(0, ar[i].l - mx_l));
        else if(flag2) ans[ar[i].id] = min(ans[ar[i].id], max(0, ar[i].l - mxxl));
    }
}

void work_r()
{
    int beg = 0, color = 0;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = beg + 1; br[j].l <= ar[i].r && j <= n ; ++j)
        {
            //cout << br[j].id << '\n';
            color = br[j].c;
            if(br[j].r > mxr[color])
            {
                mxr[color] = br[j].r;
                if(mxr[color] > mx_r)
                {
                    if(mxr_color == color) mx_r = mxr[color];
                    else
                    {
                        mxxr = mx_r;
                        mx_r = mxr[color];
                        mxr_color = color;
                        flag1 = true;
                        if(mxxr != -inf) flag2 = true;
                    }

                }
                else if(mxr[color] > mxxr && color != mxr_color)
                {
                    mxxr = mxr[color];
                    flag2 = true;
                }
            }
            beg = j;
        }
        if(ar[i].c != mxr_color && flag1) ans[ar[i].id] = min(ans[ar[i].id], max(0, ar[i].l - mx_r));
        else if(flag2) ans[ar[i].id] = min(ans[ar[i].id], max(0, ar[i].l - mxxr));
    }
}

int main()
{
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d%d", &ar[i].l, &ar[i].r, &ar[i].c);
            ar[i].id = i;
            br[i] = ar[i];
        }

        //cout << 1 << '\n';

        sort(ar + 1, ar + n + 1, cmp1);
        sort(br + 1, br + n + 1, cmp2);

//        for(int i = 1; i <= n; ++i) cout << i << ' ' << ar[i].l << ' ' << ar[i].r << ' ' << ar[i].id << '\n';
//        for(int i = 1; i <= n; ++i) cout << i << ' ' << br[i].l << ' ' << br[i].r << ' ' << br[i].id << '\n';

        init();

        //cout << 2 << '\n';

        work_l();

//        for(int i = 1; i <= n; ++i) printf("%d ", ans[i]);
//        putchar('\n');

        //cout << 3 << '\n';

        for(int i = 1; i <= n; ++i)
        {
            ar[i].l *= -1, ar[i].r *= -1;
            swap(ar[i].l, ar[i].r);
            br[i].l *= -1, br[i].r *= -1;
            swap(br[i].l, br[i].r);
        }

        sort(ar + 1, ar + n + 1, cmp1);
        sort(br + 1, br + n + 1, cmp2);
        flag1 = flag2 = false;

//        for(int i = 1; i <= n; ++i) cout << i << ' ' << ar[i].l << ' ' << ar[i].r << ' ' << ar[i].id << '\n';
//        for(int i = 1; i <= n; ++i) cout << i << ' ' << br[i].l << ' ' << br[i].r << ' ' << br[i].id << '\n';

        //cout << 4 << '\n';

        work_r();

        //cout << 5 << '\n';

        for(int i = 1; i <= n; ++i) printf("%d ", ans[i]);
        putchar('\n');

    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值