Codeforces 828C

题意:给出n个字符串s,对每一个字符串可以给出m个位置ki,表示可以把字符串填到ki~ki+len(s)上,保证不会冲突,求最后符合条件的字典序最小字符串。


尝试用线段树写了一下
设置一个tag标记,如果区间整个都做过修改,tag为真,下次碰到这个区间后就直接跳过了

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 2e6 + 10;
char ans[maxn];

struct Tree{
    int l, r;
    bool tag;
};
Tree t[maxn<<2];

void build(int l, int r, int root)
{
    t[root].l = l, t[root].r = r;
    t[root].tag = false;
    if(t[root].l != t[root].r){
        int mid = (t[root].l + t[root].r) >> 1;
        build(l, mid, root << 1);
        build(mid + 1, r, root << 1 | 1);
    }
}

void update(int l, int r, string &s, int root)
{
    if(t[root].tag) return;
    else if((t[root].l == t[root].r)){
        ans[t[root].l] = s[t[root].l - l];
        t[root].tag = true;
        return;
    }
    else{
        int mid = (t[root].l + t[root].r) >> 1;
        if(r <= mid) update(l, r, s, root << 1);
        else if(l > mid) update(l, r, s, root << 1 | 1);
        else{
            update(l, r, s, root << 1);
            update(l, r, s, root << 1 | 1);
        }
        if(t[root << 1].tag && t[root << 1 | 1].tag)
            t[root].tag = true;
    }
}

string s[maxn];
vector<int> a[maxn];

int main()
{
    int n; scanf("%d", &n);
    for(int i = 0; i < n; i++) a[i].clear();
    int Max = 0;
    for(int i = 0; i < n; i++){
        cin>>s[i];
        int m; scanf("%d", &m);
        int len = s[i].length();
        for(int j = 0; j < m; j++){
            int temp; scanf("%d",&temp);
            a[i].push_back(temp);
            Max = max(Max, len + temp - 1);
        }
    }
    for(int i = 0; i <= Max+10; i++)
        ans[i] = 'a';
    build(0, Max, 1);
    for(int i = 0; i < n; i++){
        int len = s[i].length();
        for(int j = 0; j < a[i].size(); j++){
            update(a[i][j]-1, a[i][j]+len-2, s[i], 1);
        }
    }
    for(int i = 0; i < Max; i++)
        printf("%c",ans[i]);
    return 0;
}
posted @ 2017-07-17 22:28  />.<\  阅读(176)  评论(0编辑  收藏  举报