【线段树||set遍历】Codeforces Round #207 (Div. 1) A. Knight Tournament

 Codeforces Round #207 (Div. 1) A. Knight Tournament

题意:

  • n个骑士(编号1-n),有m场battle,保证每一场battle的人数>=2。给出m场battle的信息:每一场battle的信息是:给出一个区间[l, r],再给出一个该场battle的胜利者编号won,意思就是说[l, r]中还没有被打败的骑士都会在这一场被won打败了。问,输出1-n的每一个骑士是被哪个骑士打败的,其中赢得最后胜利的骑士输出0。

思路1:用线段树维护区间是被谁打败的。初始化肯定是0。然后输入一个区间,如果这个区间 还没有被打败过(lazy[rt] == 0)就将这个区间的lazy标记为won。pushdown更新儿子的时候也是要判断lazy[lsn]和lazy[rsn]是不是为0,为0才更新为lazy[rt],否则不更新。

//280ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll maxN = 3e5 + 5;

int n, m;
int lazy[maxN << 2];
void init() { memset(lazy, 0, sizeof(lazy)); }
void pushdown(int rt, int l, int r)
{
    if(lazy[rt])
    {
        int mid = MID;
        if(! lazy[lsn])
            lazy[lsn] = lazy[rt];
        if(! lazy[rsn])
            lazy[rsn] = lazy[rt];
        lazy[rt] = 0;
    }
}
void update(int rt, int l, int r, int ql, int qr, int val)
{
    if(ql <= l && qr >= r)
    {
        if(!lazy[rt])
            lazy[rt] = val;
        return;
    }
    pushdown(rt, l, r);
    int mid = MID;
    if(qr <= mid)
        update(QL, val);
    else if(ql > mid)
        update(QR, val);
    else { update(QL, val); update(QR, val); }
}
int query(int rt, int l, int r, int dot)
{
    if(l == r)
        return lazy[rt];
    pushdown(rt, l, r);
    int mid = MID;
    if(dot <= mid)
        return query(Lson, dot);
    else if(dot > mid)
        return query(Rson, dot);
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        init();
        while(m -- )
        {
            int l, r, won;
            scanf("%d%d%d", &l, &r, &won);
            if(l <= won - 1)
                update(1, 1, n, l, won - 1, won);
            if(won + 1 <= r)
                update(1, 1, n, won + 1, r, won);
        }
        for(int i = 1; i <= n; i ++ )
            printf("%d%c", query(1, 1, n, i), " \n"[i == n]);
    }
    return 0;
}
/*
8 1
1 8 8
 */
/*
300000 10
1 10 1
1 100 1
1 1000 1
1 10000 1
1 100000 1
1 200000 1
1 200020 1
1 200700 1
1 299999 1
1 300000 300000
 */

 思路2:倒序覆盖。其实倒着覆盖,就是一个染色问题。

//265ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 3e5 + 5;
int n, m;
struct node{
    int l, r, won;
    node(int a = 0, int b = 0, int c = 0): l(a), r(b), won(c) {}
}info[maxN];
int tree[maxN << 2];
void build_tree(int rt, int l, int r)
{
    tree[rt] = 0;
    if(l == r) return;
    int mid = MID;
    build_tree(Lson);
    build_tree(Rson);
}
void pushdown(int rt)
{
    if(tree[rt])
    {
        tree[lsn] = tree[rt]; tree[rsn] = tree[rt];
        tree[rt] = 0;
    }
}
void update_range(int rt, int l, int r, int ql, int qr, int val)
{
    if(ql <= l && qr >= r)
    {
        tree[rt] = val;
        return;
    }
    pushdown(rt);
    int mid = MID;
    if(qr <= mid) update_range(QL, val);
    else if(ql > mid) update_range(QR, val);
    else { update_range(QL, val); update_range(QR, val); }
}
int query(int rt, int l, int r, int dot)
{
    if(l == r) return tree[rt];
    pushdown(rt);
    int mid = MID;
    if(dot <= mid) return query(Lson, dot);
    else if(dot > mid) return query(Rson, dot);
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        for(int i = 1; i <= m; i ++ )
            scanf("%d%d%d", &info[i].l, &info[i].r, &info[i].won);
        build_tree(1, 1, n);
        for(int i = m; i > 0; i -- )
        {
            if(info[i].won - 1 >= info[i].l)
                update_range(1, 1, n, info[i].l, info[i].won - 1, info[i].won);
            if(info[i].won + 1 <= info[i].r)
                update_range(1, 1, n, info[i].won + 1, info[i].r, info[i].won);
        }
        for(int i = 1; i <= n; i ++ )
            printf("%d%c", query(1, 1, n, i), " \n"[i == n]);
    }
    return 0;
}
/*
8 1
1 8 8
 */
/*
300000 10
1 10 1
1 100 1
1 1000 1
1 10000 1
1 100000 1
1 200000 1
1 200020 1
1 200700 1
1 299999 1
1 300000 300000
 */

乱七八糟的思路:

  • 最开始有想用set,但是马上就把这个想法否了(觉得一定会T的,确实也没想好到底是怎么处理吧。后来用set做了,但是不靠百度就不可能会过的,不会set的遍历,迭代器不会用。ps:话说回来我都还没有学过c++, www)

乱七八糟的正经第一个代码思路:

线段树离线查询算法。先将所有的信息存起来。然后倒序覆盖回去(正序的话显然有点诡异,因为区间中包括的骑士不全是没有被打败的,所以如果正序的话,后面更新还要记录之前已经被打败的骑士,麻烦)。倒序覆盖的话就不会影响最终结果。

所以这道题其实是更新一个区间中所有的点的值都为相同的won,但是其实区间并没有维护什么东西。所以开始我就有点迷,不知道该用线段树维护什么。最后就想,反正区间值没有什么实际意义也用不到,不如就最简单的求和吧。然后就开写了。

写完第一份代码,WA 7,(我这个人就特别不喜欢造样例,于是debug是一个非常自我折磨的过程www不知道错哪里),后来还是造了一个样例就代码下边第一个样例。发现query的时候没有pushdown。【但是不知道为什么手残把lazy的数组开了一倍,本来还是开四倍的,然后不知道为什么什么东西驱使我让我给删了】

然后交了第二份代码,WA 11,就更不知道哪里错了www。

试了很多样例都没错(因为造的都很简单www),然后就又试了代码下边第二个样例,发现跑不出来。然后调了一下发现是爆了int,3e5*3e5肯定爆了啊qaq,于是索性就所有数据类型都改了long long,然后就过了第三份代码。

线段树具体实现

初始化当然都是0,都是winner。也就是线段树建树每个结点为0。我们倒序更新所给的区间都为对应的won。把所有区间都更新完单个结点的值就是最终的答案。

【我……好菜,根本就不用求和,根本不知道在做什么,稍微卡一下空间我比赛就GG了……www,怪我上个寒假没好好学线段树染色问题。我都不知道!之前也做过一个倒序覆盖的问题,还不知道原来就是染色问题wwww】

//514ms//这个代码真的不用看了……//完全浪费了一个tree[]数组的空间
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID ((l + r ) >> 1 )
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll maxN = 3e5 + 5;

ll n, m;
struct node{
    ll s, e, won;
    node(ll a = 0, ll b = 0, ll c = 0) : s(a), e(b), won(c) {}
}info[maxN];

ll tree[maxN << 2], lazy[maxN << 2];
void init() { memset(lazy, 0, sizeof(lazy)); }
void pushup(ll rt) { tree[rt] = tree[lsn] + tree[rsn]; return; }
void pushdown(ll rt, ll l, ll r)
{
    if(lazy[rt] != 0)
    {
        ll mid = MID;
        tree[lsn] = lazy[rt] * (mid - l + 1);
        tree[rsn] = lazy[rt] * (r - mid);
        lazy[lsn] = lazy[rt];
        lazy[rsn] = lazy[rt];
        lazy[rt] = 0;
    }
}
void build_tree(ll rt, ll l, ll r)
{
    if(l == r) { tree[rt] = 0; return ;}
    ll mid = MID;
    build_tree(Lson);
    build_tree(Rson);
    pushup(rt);
}
void updata_range(ll rt, ll l, ll r, ll ql, ll qr, ll val)
{
    if(ql <= l && qr >= r)
    {
        tree[rt] = val * (r - l + 1);
        lazy[rt] = val;
        return;
    }
    pushdown(rt, l, r);
    ll mid = MID;
    if(qr <= mid)
        updata_range(QL, val);
    else if(ql > mid)
        updata_range(QR, val);
    else { updata_range(QL, val); updata_range(QR, val); }
    pushup(rt);
}
ll query(ll rt, ll l, ll r, ll dot)
{
    if(l == r)
        return tree[rt];
    pushdown(rt, l, r);
    ll mid = MID;
    if(dot <= mid)
        return query(Lson, dot);
    else if(dot > mid)
        return query(Rson, dot);
}
int main()
{
    while(~scanf("%lld%lld", &n, &m))
    {
         init();
         for(ll i = 1; i <= m; i ++ )
             scanf("%lld%lld%lld", &info[i].s, &info[i].e, &info[i].won);
         build_tree(1, 1, n);
         for(ll i = m; i > 0; i -- )
         {
             if(info[i].s <= info[i].won - 1)
                 updata_range(1, 1, n, info[i].s, info[i].won - 1, info[i].won);
             if(info[i].won + 1 <= info[i].e)
                 updata_range(1, 1, n, info[i].won + 1, info[i].e, info[i].won);
         }
         for(ll i = 1; i <= n; i ++ )
             printf("%lld%c", query(1, 1, n, i), " \n"[i == n]);
    }
    return 0;
}
/*
8 1
1 8 8
 */
/*
300000 10
1 10 1
1 100 1
1 1000 1
1 10000 1
1 100000 1
1 200000 1
1 200020 1
1 200700 1
1 299999 1
1 300000 300000
 */

 下边两个都是set的做法。确实快,O(n)。

思路就是,将所有1-n插入set。然后每输入一个区间,就把整个区间里的值erase掉,并且存ans[] = won,完了之后就再将won插入set。直到跑完所有的区间,那么set里还剩余的那个就是final winner,将它的ans[]赋值为0.

除了迭代器的使用之外,还有一个erase的诡异用法。

  1. 如果erase了一个it指向的内容,那这个迭代器也被删了。所以要在被删之前保存一下it。那当然简单又高大上的处理就是st.erase(iter ++ );

  2. 还有一种处理是iter = st.erase(iter);. 因为删除了iter指向的内容之后就会指向下一个元素的地址。所以就是直接更新iter的位置为下一个元素的地址即可。

  3. vector的迭代器和这个又不一样。对于vector来说,删除了一个元素之后,下一个元素会移动到被删元素原来的位置,也就是iter是不变的。

//343ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID ((l + r ) >> 1 )
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 3e5 + 5;
int n, m;
int ans[maxN];
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        memset(ans, 0, sizeof(ans));
        set<int>st;
        set<int>::iterator iter;
        for(int i = 1; i <= n; i ++ )
            st.insert(i);
        for(int i = 1; i <= m; i ++ )
        {
            int l, r, won;
            scanf("%d%d%d", &l, &r, &won);
            iter = st.lower_bound(l);
            while(iter != st.end() && *iter <= r)
            {
                ans[*iter] = won;
                iter = st.erase(iter);//删除元素之后指向下一个元素的位置
                //st.erase(iter ++ );也可。解释:删除该迭代器指向的内容之后iter被删除,所以在删除指针之前对其做一个备份
                //如果是vector那么删除元素后,后面的元素自动前移,不用挪动指针也就是:vt.erase(it);
            }
            st.insert(won);
        }
        int won = *st.begin();
        ans[won] = 0;
        for(int i = 1; i <= n; i ++ )
            printf("%d%c", ans[i], " \n"[i == n]);
    }
    return 0;
}

 为了避免上边erase的iter的诡异变化,就直接删除区间。(我才知道可以删除区间,tcl)

//358ms
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID ((l + r ) >> 1 )
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 3e5 + 5;
int n, m;
int ans[maxN];
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        memset(ans, 0, sizeof(ans));
        set<int>st;
        set<int>::iterator iter;
        for(int i = 1; i <= n; i ++ )
            st.insert(i);
        for(int i = 1; i <= m; i ++ )
        {
            int l, r, won;
            scanf("%d%d%d", &l, &r, &won);
            iter = st.lower_bound(l);
            while(iter != st.end() && *iter <= r)
            {
                ans[*iter] = won;
                iter ++;
            }
            st.erase(st.lower_bound(l), iter);
            st.insert(won);
        }
        int won = *st.begin();
        ans[won] = 0;
        for(int i = 1; i <= n; i ++ )
            printf("%d%c", ans[i], " \n"[i == n]);
    }
    return 0;
}
发布了180 篇原创文章 · 获赞 54 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/103945017