返回顶部

牛客练习赛91 C.魔法学院(hard version) (dsu区间染色)

离线将所有信息存下来,按照字符的大小排序,不难发现,字符ascii越大的最后覆盖最优,那么我们选最大的覆盖,同时并查集维护覆盖过的区间,即让每个节点的父亲都等于它右边的节点,对于每个区间我们跑\([l_i,r_i]\),每次更新\(l\)\(p[l+1]\),这样遇到覆盖过的区间就直接跳过,那么复杂度为\(O(n+m)\).

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define ll long long
#define ull unsigned long long
#define PLL pair<ll,ll>
const int N=10000010;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;


struct Node{
    int l,r;
    char c;
}e[N];

int n,m;
char s[N];
int p[N];

int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}


int main(){
    scanf("%d %d",&n,&m);
    getchar();
    scanf("%s",s+1);
    for(int i=1;i<=m;++i){
        scanf("%d %d %c",&e[i].l,&e[i].r,&e[i].c);
    }
    sort(e+1,e+1+m,[&](Node a,Node b){
            return a.c<b.c;
    });
    for(int i=1;i<=n+1;++i) p[i]=i;
    for(int i=m;i>=1;--i){
        int l=e[i].l,r=e[i].r;
        char c=e[i].c;
        while(l<=r){
            if(c>s[l]) s[l]=c;
            p[l]=l+1;
            l=find(p[l+1]);
        }
    }
    ll res=0;
    for(int i=1;i<=n;++i) res+=s[i];
    printf("%lld\n",res);
    return 0;
}




posted @ 2021-11-13 19:55  Rayotaku  阅读(57)  评论(0编辑  收藏  举报