P7563 JOISC 2021 Day4 最悪の記者 4 (Worst Reporter 4)

线段树合并好题,通过线段树合并特别的方式优化了树形 dp。

思路

根据图中的不等关系连边建图,不难发现最后的图将会是基环树森林和普通的树的森林,我们先考虑对于一棵树要怎么办。

将 \(h_i\) 离散化,\(m\) 为离散化上界,使用树形 dp。

设 \(f_{i,j}\) 为将 \(i\) 改成 \(j\) 使 \(i\) 的子树内满足不等关系的最小花费。

\[f_{i,j}=c_i\times[j\neq h_i]+\sum_{k\in i.sons} \min_{j\leq t \leq m} f_{k,t}
\]

这个 dp 是超时的,但是是正确的,我们考虑优化 dp 转移。

我们发现每个都加上 \(c_i\) 对我们操作有点麻烦,我们在最后求出答案是同一加上 \(\sum c_i\),将方程改为

\[f_{i,j}=\sum_{k\in i.sons}\min_{j\leq t\leq m} f_{k,t} -c_i*[j=h_i]
\]

为什么这样操作呢?

由于转移只有区间最小值查询和减法操作,考虑线段树维护 \(f\) 值。

线段树的区间维护一个节点的状态的第二维,点取值维护对应区间的最小值,区间 \([l,r]\) 维护的是 \(\min_{l\leq i\leq r} f_{u,i}\)。

每个点开一棵肯定不现实,考虑线段树合并,每一次合并就相当于父亲和儿子做一次转移。

找区间最小值的区间是 \([j,m]\),合并树 \(u\) 和树 \(v\) 时,计 \(u_{min}\) 和 \(v_{min}\) 为各自的最小值(在区间 \([j,m]\) 内),对于节点 \(p\) 和 \(q\) 分类讨论 \(p+v_{min}\) 和 \(q+u_{min}\) 哪个最小(这里实际上和转移有关,可以钦定父子关系,从转移方程的角度分析),将较小值设置即可。

由于最小值右端点固定,启发性的先合并右子树,便于维护最小值。

对于每个点的初始更新,在 \([h_i,h_i]\) 出加上 \(-c_i\) 即可。

扩展到基环树,发现基环树的环上的点肯定是同一取值,且要么是 \(1\) 要么是环上取值。

那么先求出基环树的环上节点的 \(f\) 状态,最后枚举环上的点的取值即可。

CODE

#include<bits/stdc++.h>
using namespace std; #define ll long long
#define lch(p) tree[p].lch
#define rch(p) tree[p].rch const int maxn=2e5+5; int rb; struct linetree
{
int tot;
ll d1,d2;
struct treenode{int lch,rch;ll lazy,mi;}tree[maxn*57];
void push_down(int p)//下传懒标记
{
if(!tree[p].lazy) return ;
ll &lazy=tree[p].lazy;
if(lch(p)) tree[lch(p)].lazy+=lazy,tree[lch(p)].mi+=lazy;
if(rch(p)) tree[rch(p)].lazy+=lazy,tree[rch(p)].mi+=lazy;
lazy=0;
}
void updata(int p)
{
tree[p].mi=min(tree[lch(p)].mi,tree[rch(p)].mi);
}
void insert(int &p,int l,int r,int x,ll y)
{
if(l>x||r<x) return ;
if(!p) p=++tot;
if(l==r){tree[p].mi=y;return ;}
push_down(p);
int mid=(l+r)>>1;
insert(lch(p),l,mid,x,y);
insert(rch(p),mid+1,r,x,y);
updata(p);
}
ll qry(int p,int l,int r,int lx,int rx)//查询区间最小值
{
if(!p) return 0;
if(lx<=l&&r<=rx) return tree[p].mi;
if(lx>r||rx<l) return 0;
push_down(p);
int mid=(l+r)>>1;
return min(qry(lch(p),l,mid,lx,rx),qry(rch(p),mid+1,r,lx,rx));
}
void merge(int &p1,int p2,int l,int r)//合并
{
if(!p1&&!p2) return ;
if(!p1)
{
d2=min(d2,tree[p2].mi);
tree[p2].mi+=d1;
tree[p2].lazy+=d1;
p1=p2;
return ;
}
else if(!p2)
{
d1=min(d1,tree[p1].mi);
tree[p1].mi+=d2;
tree[p1].lazy+=d2;
return ;
}
if(l==r)
{
d1=min(d1,tree[p1].mi),d2=min(d2,tree[p2].mi);
if(tree[p1].mi+d2<=tree[p2].mi+d1){tree[p1].mi=tree[p1].mi+d2;}
else{tree[p1].mi=tree[p2].mi+d1;}
return ;
}
push_down(p1);
push_down(p2);
int mid=(l+r)>>1;
merge(rch(p1),rch(p2),mid+1,r);//启发式
merge(lch(p1),lch(p2),l,mid);
updata(p1);
}
void premrg(int &x,int y)
{
d1=d2=0;
merge(x,y,1,rb);
}
}T;
struct Edge
{
int tot;
int head[maxn];
struct edgenode{int to,nxt;}edge[maxn*2];
void add(int u,int v)
{
tot++;
edge[tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot;
}
}E; int n,tot;
int a[maxn],h[maxn],c[maxn],ind[maxn],d[maxn],dfn[maxn];
int rt[maxn],nt[maxn]; struct node{ll h,c;};
bool cmp(node a,node b){return a.h<b.h;}
vector<node>cr[maxn]; ll ans; void pushcir(int u)//同一个环赋予同一编号
{
dfn[u]=tot;
cr[tot].push_back({h[u],c[u]});
if(!dfn[a[u]]) pushcir(a[u]);
}
void gtp()//找环
{
queue<int>que;
while(!que.empty()) que.pop();
for(int i=1;i<=n;i++) if(!ind[i]) que.push(i);
while(!que.empty())
{
int u=que.front();que.pop();
if(!--ind[a[u]]) que.push(a[u]);
}
for(int i=1;i<=n;i++)//可能有多个环,tot 是环数
if(!dfn[i]&&ind[i]) tot++,pushcir(i);
}
void dfs(int u)//求 u 的状态
{
for(int i=E.head[u];i;i=E.edge[i].nxt)
{
int v=E.edge[i].to;
dfs(v);
T.premrg(rt[u],rt[v]);//合并儿子和自己
}
T.insert(rt[u],1,rb,h[u],T.qry(rt[u],1,rb,h[u],rb)-c[u]);
//insert 更改区间 [h[u],h[u]] 的值
}
void calc()
{
for(int i=1;i<=n;i++) if(!ind[i]&&ind[a[i]])//求环的状态
dfs(i),T.premrg(nt[dfn[a[i]]],rt[i]);
for(int i=1;i<=tot;i++)
{
sort(cr[i].begin(),cr[i].end(),cmp);
ll cnt=T.tree[nt[i]].mi,sh=cr[i][0].h,sc=0;
for(node v:cr[i])
{
if(v.h==sh) sc+=v.c;
else
{
cnt=min(cnt,T.qry(nt[i],1,rb,sh,rb)-sc);
sh=v.h,sc=v.c;
}
}
cnt=min(cnt,T.qry(nt[i],1,rb,sh,rb)-sc);
ans+=cnt;
}
} int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i],&h[i],&c[i]);
E.add(a[i],i);
ind[a[i]]++;
d[i]=h[i];
ans+=c[i];
}
sort(d+1,d+n+1);
rb=unique(d+1,d+n+1)-d-1;
for(int i=1;i<=n;i++) h[i]=lower_bound(d+1,d+rb+1,h[i])-d;//离散化
gtp();
calc();
printf("%lld",ans);
}

P7563 JOISC 2021 Day4 最悪の記者 4 (Worst Reporter 4)的更多相关文章

  1. LOJ#2882. 「JOISC 2014 Day4」两个人的星座(计算几何)

    题面 传送门 题解 我们发现如果两个三角形相离,那么这两个三角形一定存在两条公切线 那么我们可以\(O(n^2)\)枚举其中一条公切线,然后可以暴力\(O(n^3)\)计算 怎么优化呢?我们可以枚举一 ...

  2. @loj - 3039@ 「JOISC 2019 Day4」蛋糕拼接 3

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 今天是 IOI 酱的生日,所以她的哥哥 JOI 君给她预定了一个 ...

  3. 「JOISC 2020 Day4」首都城市

    题目   点这里看题目. 分析   做法比较容易看出来.我们对于每个城市,找出那些 " 如果这个城市在首都内,则必须在首都内的其它城市 " ,也就是为了让这个城市的小镇连通而必须选 ...

  4. 「JOISC 2014 Day4」两个人的星座

    首先突破口肯定在三角形不交,考虑寻找一些性质. 引理一:两个三角形不交当且仅当存在一个三角形的一条边所在直线将两个三角形分为异侧 证明可以参考:三角形相离充要条件,大致思路是取两个三角形重心连线,将其 ...

  5. Solution -「JOISC 2021」古老的机器

    \(\mathcal{Description}\)   Link.   这是一道通信题.   对于长度为一个 \(n\),仅包含字符 X, Y, Z 的字符串 \(s\),将其中 \(n\) 个字符按 ...

  6. Solution -「JOISC 2021」「LOJ #3489」饮食区

    \(\mathcal{Description}\)   Link.   呐--不想概括题意,自己去读叭~ \(\mathcal{Solution}\)   如果仅有 1. 3. 操作,能不能做?    ...

  7. Solution -「JOISC 2021」「LOJ #3495」聚会 2

    \(\mathcal{Description}\)   Link.   给定一棵含 \(n\) 个结点的树.称点集 \(S\) 到结点 \(u\) 的会合距离为 \(\sum_{v\in S}\ope ...

  8. Solution -「JOISC 2021」「LOJ #3491」道路建设

    \(\mathcal{Description}\)   Link.   平面上有 \(n\) 个互不重合的点 \((x_{1..n},y_{1..n})\),求其两两曼哈顿距离的前 \(m\) 小值. ...

  9. 「JOISC 2019 Day4」蛋糕拼接 3

    loj 3039 NKOJ Description \(n\)个蛋糕,每个蛋糕有\(w_i,h_i\).选\(m\)个蛋糕满足\(\sum\limits_{j=1}^mw_{k_j}-\sum\lim ...

  10. Solution -「简单 DP」zxy 讲课记实

    魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...

随机推荐

  1. 为什么重写hashCode一定也要重写equals方法?

    这是一个经典的问题,我们先从==开始看起 == "==" 是运算符 如果比较的对象是基本数据类型,则比较的是其存储的值是否相等: 如果比较的是引用数据类型,则比较的是所指向对象的地 ...

  2. 《Programming from the Ground Up》阅读笔记:p103-p116

    <Programming from the Ground Up>学习第7天,p103-p116总结,总计14页. 一.技术总结 1.读写文件 (1)linux.s linux.s: #fi ...

  3. 异源数据同步 → DataX 为什么要支持 kafka?

    开心一刻 昨天发了一条朋友圈:酒吧有什么好去的,上个月在酒吧当服务员兼职,一位大姐看上了我,说一个月给我 10 万,要我陪她去上海,我没同意 朋友评论道:你没同意,为什么在上海? 我回复到:上个月没同 ...

  4. Devexpress GridView 单元格输入检验

    实现效果 打开设计器 找到CellValueChanged事件 编写代码 private void gvmain_CellValueChanged(object sender, DevExpress. ...

  5. 【Jenkins】Mac系统之忘记jenkins密码,如何修改密码

    参考文章<jenkins管理员密码登录不了> 一.修改config.xml文件 Mac下的文件在 /Users/xxx/.jenkins/users/登录的用户名/config.xml 复 ...

  6. SpringBoot启动项目报错:java.lang.UnsatisfiedLinkError: D:\files\software\jdk-15.0.1\jdk-17.0.3.1\bin\tcnative-1.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

    目录 问题描述 解决方法: 问题描述 在运行向的时候出现报错: java.lang.UnsatisfiedLinkError: D:\files\software\jdk-15.0.1\jdk-17. ...

  7. 性能、成本与 POSIX 兼容性比较: JuiceFS vs EFS vs FSx for Lustre

    JuiceFS 是一款为云环境设计的分布式高性能文件系统.Amazon EFS 易于使用且可伸缩,适用于多种应用.Amazon FSx for Lustre 则是面向处理快速和大规模数据工作负载的高性 ...

  8. AWS Cloud Practioner 官方课程笔记 - Part 3

    AWS Security 方案和功能 Amazon Inspector AWS Shield Price and Support Free Tier: Always Free, 12-month fr ...

  9. kubernetes重新初始化“[ERROR DirAvailable--var-lib-etcd]”

    [root@master01 ~]# kubeadm init --config /root/kubeadm-config.yaml --upload-certs [init] Using Kuber ...

  10. ArgoWorkflow教程(四)---Workflow & 日志归档

    上一篇我们分析了argo-workflow 中的 artifact,包括 artifact-repository 配置以及 Workflow 中如何使用 artifact.本篇主要分析流水线 GC 以 ...