[清华集训 2017] 某位歌姬的故事

题目大意

给定 \(n\)\(m\),同时给定 \(q\) 条形如 \((l_i,r_i,m_i)\) 的限制,求满足以下条件的长度为 \(n\) 的数组 \(a\) 的个数:

  • \(\displaystyle\forall 1\leq i\leq n\),有 \(1\leq a_i \leq m\)

  • \(\displaystyle\forall 1\leq i\leq q\),有 \(\max_{i=l_i}^{r_i} a_i = m_i\)

数据范围

  • \(1\leq n,m\leq 8\times 10^7\)

  • \(1\leq q\leq 10^5\)

题解

首先离散化,其次可以通过使用任意的数据结构求得每个位置取值的上界,即 \(lim_i=\min\{m_j|1\leq j\leq q\wedge l_j\leq i\leq r_j\}\)

不难发现,询问 \(i\) 的结果仅和 \(lim_j=m_i\)\(j\) 有关,于是将 \(m_i\)\(lim_j\) 相同的划分在一起做,然后就是 Intervals 了。

#include<bits/stdc++.h>

using namespace std;

const int N=1e5+9;
const int mod=998244353;
inline void AddAs(int &x,int y){if((x+=y)>=mod) x-=mod;}
inline void SubAs(int &x,int y){if((x-=y)<0) x+=mod;}
inline void MulAs(int &x,int y){x=1ll*x*y%mod;}
inline int Add(int x,int y){if((x+=y)>=mod) x-=mod;return x;}
inline int Sub(int x,int y){if((x-=y)<0) x+=mod;return x;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline int QPow(int x,int y){
    int res=1;
    while(y){
        if(y&1) res=1ll*res*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return res;
}
#define Inv(x) QPow(x,mod-2)

int ql[N],qr[N],qk[N],n,m,q,tot,num;
vector<int> val,tmp;
inline void Disc(){
    for(int i=1;i<=q;i++){
        val.push_back(ql[i]);
        val.push_back(qr[i]+1);
        tmp.push_back(qk[i]);
    }
    val.push_back(0);
    val.push_back(1);
    val.push_back(n+1);
    tmp.push_back(0);
    tmp.push_back(m+1);
    sort(val.begin(),val.end());
    sort(tmp.begin(),tmp.end());
    val.erase(unique(val.begin(),val.end()),val.end());
    tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
    tot=val.size()-2;
    num=tmp.size()-1;
    for(int i=1;i<=q;i++){
        ql[i]=lower_bound(val.begin(),val.end(),ql[i])-val.begin();
        qr[i]=upper_bound(val.begin(),val.end(),qr[i])-val.begin()-1;
        qk[i]=lower_bound(tmp.begin(),tmp.end(),qk[i])-tmp.begin();
    }
}
int lim[N];
vector<int> st[N],ed[N],pnt[N],qry[N];
inline void GetLim(){
    for(int i=1;i<=q;i++) st[ql[i]].push_back(i);
    for(int i=1;i<=q;i++) ed[qr[i]].push_back(i);
    priority_queue<int> p,r;
    p.push(-num);
    for(int i=1;i<=tot;i++){
        for(int j:st[i]) p.push(-qk[j]);
        while(r.size()&&p.top()==r.top()) p.pop(),r.pop();
        lim[i]=-p.top();
        for(int j:ed[i]) r.push(-qk[j]);
    }
    for(int i=1;i<=tot;i++) pnt[lim[i]].push_back(i);
    for(int i=1;i<=q;i++) qry[qk[i]].push_back(i);
}
int f[N],lp[N];
inline int Work(int k){
    if(tmp[k]==1) return 1;
    const int n=pnt[k].size();
    pnt[k].insert(pnt[k].begin(),0);
    for(int i=0;i<=n;i++) lp[i]=-1;
    for(int i:qry[k]){
        int l=lower_bound(pnt[k].begin(),pnt[k].end(),ql[i])-pnt[k].begin();
        int r=upper_bound(pnt[k].begin(),pnt[k].end(),qr[i])-pnt[k].begin()-1;
        if(l>r) return 0;
        lp[r]=max(lp[r],l);
    }
    int sum=f[0]=1,tag=1;
    for(int i=1,j=0;i<pnt[k].size();i++){
        int w0=QPow(tmp[k]-1,val[pnt[k][i]+1]-val[pnt[k][i]]);
        int w1=Sub(QPow(tmp[k],val[pnt[k][i]+1]-val[pnt[k][i]]),w0);
        MulAs(tag,w0);
        f[i]=Mul(Inv(tag),Mul(sum,w1));
        MulAs(sum,w0);
        AddAs(sum,Mul(f[i],tag));
        while(j<lp[i]) SubAs(sum,Mul(f[j++],tag));
    }
    return sum;
}

inline void Clear(){
    val.clear();
    tmp.clear();
    for(int i=1;i<=tot;i++){
        st[i].clear();
        ed[i].clear();
        f[i]=lp[i]=0;
    }
    for(int i=1;i<=num;i++){
        pnt[i].clear();
        qry[i].clear();
    }
}

signed main(){
    int T;
    cin>>T;
    while(T--){
        cin>>n>>q>>m;
        for(int i=1;i<=q;i++) cin>>ql[i]>>qr[i]>>qk[i];
        Disc();

        int ans=1;
        GetLim();
        // for(int i=1;i<=tot;i++) cout<<val[i]<<' ';cout<<endl;
        // for(int i=1;i<=tot;i++) cout<<lim[i]<<' ';cout<<endl;
        for(int i=1;i<num;i++) MulAs(ans,Work(i));
        for(int i:pnt[num]) MulAs(ans,QPow(m,val[i+1]-val[i]));
        Clear();

        cout<<ans<<endl;
    }

    return 0;
}
posted @ 2025-03-24 11:14  JoeyJiang  阅读(15)  评论(0)    收藏  举报