UOJ621 【JOISC2021】最差记者 4

UOJ621 【JOISC2021】最差记者 4

线段树合并

从早上研究到晚上,终于干掉了这道题UOJ621 【JOISC2021】最差记者 4

对于题目中rating关系建图。

首先,每个点的出度为\(1\),因此整张图是由多个基环内向树组成的,我们需要对于每个基环内向树计算答案,相加即可。

容易发现,在一棵基环内向树上,环上点的权值必然相等。

我们先考虑树的情况,需要满足子节点的权值\(\ge\)父节点的权值,可以发现最优方案中,父节点的权值一定是保持自己的权值不变,或者取子节点中的最小权值。然后再考虑叶子节点,显然它的权值要么保持不变,要么取\(INF=10^9\)。

因此在一棵大小为\(n\)的基环内向树中,节点权值取值范围最多只有\(n+1\)个数。我们可以进行\(dp\),维护一个子树的根节点权值等于任意在其子树内节点权值(或\(INF\))时的最小代价。考虑到从子节点推到父节点,比如两棵根节点权值分别为\(s,t(s<t)\)的子树,最终我们会将他们俩组成的答案合并到\(s\)中,这个可以在线段树合并的过程中实现。最终,对于一棵树,我们可以取出根节点的权值等于任意在其子树内的节点权值(或\(INF\))情况下的最小代价。

因此,对于一棵基环内向树,我们先处理每棵子树,然后直接枚举每个权值来计算答案。对于枚举的权值\(V\)来说,每棵子树根节点的权值必须\(\ge V\),我们可以默认根节点权值必须更改,然后对于那些根节点权值不更改的进行特判。

我们优化这一过程,从大到小枚举权值,然后对于每棵子树,不断拓展它的取值范围,这可以用优先队列进行动态维护。同样,对根节点权值不更改的情况进行特判。

然后我们就解决了这道题。

时间复杂度:\(O(n \log n)\)。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define N 200005
#define M 10000005
#define ll long long
#define pr pair<int,ll>
#define mp make_pair
#define IT vector<int> :: iterator
#define pIT vector< pr > :: iterator
#define mIT map<int,bool> :: iterator
using namespace std;
const ll INF=1919191919191919;
int n,cc,a[N],h[N],c[N],d[N],rd[N],rt[N];
vector<int>e[N],val[N];
vector< pr >co[N];
queue<int>q;
map<int,bool>ht;
int z0,z[N];
bool vis[N];
int cnt,n1,n2;
ll ans,sz[N],g[N];
#define ls(p) tr[p].ch[0]
#define rs(p) tr[p].ch[1]
#define mn(p) tr[p].Mn
#define tag(p) tr[p].Tag
struct node
{
    int ch[2];
    ll Mn,Tag;
}tr[M];
void push_tag(int p,ll z)
{
    if (!p)
        return;
    mn(p)+=z,tag(p)+=z;
    mn(p)=min(mn(p),INF),tag(p)=min(tag(p),INF);
}
void push_down(int p)
{
    if (tag(p))
    {
        push_tag(ls(p),tag(p));
        push_tag(rs(p),tag(p));
        tag(p)=0;
    }
}
void update(int p)
{
    mn(p)=min(mn(ls(p)),mn(rs(p)));
}
void modify(int &p,int l,int r,int x,int y)
{
    if (!p)
        p=++cnt;
    if (l==r)
    {
        mn(p)+=y;
        return;
    }
    push_down(p);
    int mid(l+r >> 1);
    if (x<=mid)
        modify(ls(p),l,mid,x,y); else
        modify(rs(p),mid+1,r,x,y);
    update(p);
}
void modify2(int &p,int l,int r,int x,ll y)
{
    if (!p)
        p=++cnt;
    if (l==r)
    {
        mn(p)=y;
        return;
    }
    push_down(p);
    int mid(l+r >> 1);
    if (x<=mid)
        modify2(ls(p),l,mid,x,y); else
        modify2(rs(p),mid+1,r,x,y);
    update(p);
}
int combine(int x,int y,int l,int r,ll xm,ll ym)
{
    if (!x && y)
        push_tag(y,xm);
    if (x && !y)
        push_tag(x,ym);
    if (!x || !y)
        return x|y;
    if (l==r)
    {
        mn(x)=min(mn(x)+min(ym,mn(y)),mn(y)+min(xm,mn(x)));
        return x;
    }
    push_down(x),push_down(y);
    int mid(l+r >> 1);
    ls(x)=combine(ls(x),ls(y),l,mid,min(xm,mn(rs(x))),min(ym,mn(rs(y))));
    rs(x)=combine(rs(x),rs(y),mid+1,r,xm,ym);
    update(x);
    return x;
}
ll calc(int p,int l,int r,int x,int y)
{
    if (!p)
        return INF;
    if (l==x && r==y)
        return mn(p);
    push_down(p);
    int mid(l+r >> 1);
    if (y<=mid)
        return calc(ls(p),l,mid,x,y); else
    if (x>mid)
        return calc(rs(p),mid+1,r,x,y); else
        return min(calc(ls(p),l,mid,x,mid),calc(rs(p),mid+1,r,mid+1,y));
}
void dfs(int p,int l,int r,int u)
{
    if (!p)
        return;
    if (l==r)
    {
        co[u].push_back(mp(l,mn(p)));
        return;
    }
    push_down(p);
    int mid(l+r >> 1);
    dfs(ls(p),l,mid,u),dfs(rs(p),mid+1,r,u);
}
void dfs(int u)
{
    ht[h[u]]=true;
    vis[u]=true;
    sz[u]=c[u];
    int ct(0);
    for (IT it=e[u].begin();it!=e[u].end();++it)
    {
        int v(*it);
        if (v==n1 || v==n2)
            continue;
        ++ct;
    }
    if (!ct)
    {
        modify(rt[u],1,cc,h[u],0);
        modify(rt[u],1,cc,cc,c[u]);
    } else
    {
        for (IT it=e[u].begin();it!=e[u].end();++it)
        {
            int v(*it);
            if (v==n1 || v==n2)
                continue;
            dfs(v);
            sz[u]+=sz[v];
            if (!rt[u])
                rt[u]=rt[v]; else
                rt[u]=combine(rt[u],rt[v],1,cc,INF,INF);
        }
        ll zt(calc(rt[u],1,cc,h[u],cc));
        push_tag(rt[u],c[u]);
        modify2(rt[u],1,cc,h[u],zt);
    }
}
struct node2
{
    pIT it;
    int id;
    node2 () {}
    node2 (pIT It,int Id):it(It),id(Id) {}
    bool operator < (const node2 &A) const
    {
        return it->first<A.it->first;
    }
};
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        scanf("%d%d%d",&a[i],&h[i],&c[i]),e[a[i]].push_back(i),++rd[a[i]],d[i]=h[i];
    sort(d+1,d+n+1);
    cc=unique(d+1,d+n+1)-d-1;
    for (int i=1;i<=n;++i)
        h[i]=lower_bound(d+1,d+cc+1,h[i])-d;
    ++cc;
    for (int i=1;i<=n;++i)
        if (!rd[i])
            q.push(i);
    while (!q.empty())
    {
        int u(q.front());
        vis[u]=true;
        q.pop();
        --rd[a[u]];
        if (!rd[a[u]])
            q.push(a[u]);
    }
    mn(0)=INF;
    for (int i=1;i<=n;++i)
        if (!vis[i])
        {
            z0=0;
            z[++z0]=i;
            for (int j=a[i];j!=i;j=a[j])
                z[++z0]=j;
            ll oc(0);
            priority_queue<node2>Q;
            for (int j=1;j<=z0;++j)
            {
                n1=(j==1)?z[z0]:z[j-1];
                n2=(j==z0)?z[1]:z[j+1];
                dfs(z[j]);
                modify(rt[z[j]],1,cc,h[z[j]],c[z[j]]);
                dfs(rt[z[j]],1,cc,j);
                val[h[z[j]]].push_back(j);
                g[j]=sz[z[j]];
                oc+=g[j];
                pIT it=co[j].end();
                --it;
                Q.push(node2(it,j));
            }
            ht[cc]=true;
            ll tas(INF);
            mIT mt=ht.end();
            --mt;
            for (;;--mt)
            {
                int x(mt->first);
                while (!Q.empty() && (Q.top().it->first)>=x)
                {
                    int u(Q.top().id);
                    pIT it(Q.top().it);
                    Q.pop();
                    oc-=g[u];
                    g[u]=min(g[u],it->second);
                    oc+=g[u];
                    if (it!=co[u].begin())
                        --it,Q.push(node2(it,u));
                }
                tas=min(tas,oc);
                ll kt(oc);
                for (IT it=val[x].begin();it!=val[x].end();++it)
                {
                    int u(*it);
                    ll vt(calc(rt[z[u]],1,cc,x,x));
                    kt+=min(0LL,vt-c[z[u]]-g[u]);
                }
                val[x].clear();
                tas=min(tas,kt);
                if (mt==ht.begin())
                    break;
            }
            ans+=tas;
            for (int j=1;j<=z0;++j)
                co[j].clear();
            ht.clear();
        }
    printf("%lld\n",ans);
    return 0;
}
上一篇:对数函数


下一篇:[AGC028D] Chords