正题

题目链接:https://loj.ac/p/3026


题目大意

给出\(n\)个点的一棵外向树,然后\(m\)个字符串和费用表示你每次可以花费这个费用覆盖路径字符串和给出字符串相等的路径,求覆盖所有边的最小花费(可以重复覆盖)

输出方案

\(1\leq n\leq 500,1\leq m\leq10^5,\sum |S|\leq 10^6\)


解题思路

注意到\(n\)很小,可以考虑枚举计算所有路径的最小花费,先构一个\(Trie\)即可处理这部分。

然后考虑怎么覆盖的问题,和[NOI2008] 志愿者招募类似的,我们可以通过边调走流来实现覆盖问题。

先原点向每一个叶子连流量为1的边,设\(siz_x\)表示\(x\)的子树中有多少个叶子那么\(x\)向\(fa_x\)连接流量为\(siz_x-1\)的边,然后根向汇点连流量为\(siz_1\)的边。

这样就保证了每条边都至少有一个流量被调走,但是需要考虑单链上的重复覆盖所以还需要每个点向儿子连无向流量的边。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const ll N=510,M=1e6+10;
struct node{
ll to,next,w;
}a[N];
ll n,m,t,tot,ans,MF,ls[N],siz[N],fa[N];
ll cnt,ch[M][26],cost[M],fail[M],mark[M];
queue<int> q;char s[M];
void addl(ll x,ll y,ll w){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;a[tot].w=w;
return;
}
void Insert(char *s,ll val,ll num){
ll x=1,m=strlen(s);
for(ll i=0;i<m;i++){
ll c=s[i]-'a';
if(!ch[x][c])ch[x][c]=++cnt;
x=ch[x][c];
}
if(cost[x]>val)cost[x]=val,mark[x]=num;
return;
}
void GetFail(){
for(ll i=0;i<26;i++)q.push(ch[1][i]);
while(!q.empty()){
ll x=q.front();
for(ll i=0;i<26;i++){
if(!ch[x][i])ch[x][i]=ch[fail[x]][i];
else{
fail[ch[x][i]]=ch[fail[x]][i];
q.push(ch[x][i]);
}
}
}
return;
}
namespace NF{
struct node{
ll to,next,w,c,typ;
}a[N*N];
ll tot=1,s,t,ls[N],f[N],mf[N],pre[N];
bool v[N];
void addl(ll x,ll y,ll w,ll c,ll mk){
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[tot].c=c;//a[tot].typ=mk;
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;a[tot].c=-c;a[tot].typ=mk;
return;
}
bool SPFA(){
memset(f,0x3f,sizeof(f));
q.push(s);v[s]=1;f[s]=0;
mf[s]=f[0];mf[t]=0;
while(!q.empty()){
ll x=q.front();v[x]=0;q.pop();
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(a[i].w&&f[x]+a[i].c<f[y]){
f[y]=f[x]+a[i].c;
pre[y]=i;mf[y]=min(mf[x],a[i].w);
if(!v[y])v[y]=1,q.push(y);
}
}
}
return mf[t];
}
void Updata(){
ll x=t;ans+=mf[t]*f[t];MF+=mf[t];
while(x!=s){
a[pre[x]].w-=mf[t];
a[pre[x]^1].w+=mf[t];
x=a[pre[x]^1].to;
}
return;
}
void GetAns(){
while(SPFA())
Updata();
return;
}
void Print(){
ll sum=0;
for(ll i=2;i<=tot;i++)
if(a[i].typ)sum+=a[i].w;
printf("%lld\n",sum);
for(ll i=2;i<=tot;i++)
if(a[i].typ){
while(a[i].w)
printf("%lld %lld %lld\n",a[i^1].to,a[i].to,a[i].typ),a[i].w--;
}
}
}
void calc(ll x,ll p,ll s){
if(!p)return;
if(cost[p]<=1e9)
NF::addl(x,s,n,cost[p],mark[p]);
for(ll i=ls[x];i;i=a[i].next)
calc(a[i].to,ch[p][a[i].w],s);
return;
}
void solve(ll x){
siz[x]+=(!ls[x]);
if(!ls[x])NF::addl(NF::s,x,1,0,0);
calc(x,1,x);
for(ll i=ls[x];i;i=a[i].next){
NF::addl(x,a[i].to,n,0,0);
solve(a[i].to),siz[x]+=siz[a[i].to];
}
if(fa[x]&&siz[x]>1)
NF::addl(x,fa[x],siz[x]-1,0,0);
return;
}
signed main()
{
memset(cost,0x3f,sizeof(cost));
scanf("%lld%lld%lld",&n,&m,&t);
for(ll i=2;i<=n;i++){
ll x;char op[3];
scanf("%lld%s",&fa[i],op);
addl(fa[i],i,op[0]-'a');
}
cnt=1;
for(ll i=1;i<=m;i++){
ll c;
scanf("%lld%s",&c,s);
Insert(s,c,i);
}
NF::s=n+1;NF::t=n+2;
solve(1);
NF::addl(1,NF::t,siz[1],0,0);
NF::GetAns();
if(MF!=siz[1])return puts("-1")&0;
printf("%lld\n",ans);
if(t)NF::Print();
return 0;
}

Loj#3026-「ROIR 2018 Day1」管道监控【Trie,费用流】的更多相关文章

  1. 2018.10.15 loj#6010. 「网络流 24 题」数字梯形(费用流)

    传送门 费用流经典题. 按照题目要求建边. 为了方便我将所有格子拆点,三种情况下容量分别为111,infinfinf,infinfinf,费用都为validi,jval_{id_{i,j}}valid ...

  2. 2018.10.15 loj#6013. 「网络流 24 题」负载平衡(费用流)

    传送门 费用流sb题. 直接从sss向每个点连边,容量为现有物品量. 然后从ttt向每个点连边,容量为最后库存量. 由于两个点之间可以互相任意运送物品,因此相邻的直接连infinfinf的边就行了. ...

  3. LOJ#2351. 「JOI 2018 Final」毒蛇越狱

    LOJ#2351. 「JOI 2018 Final」毒蛇越狱 https://loj.ac/problem/2351 分析: 首先有\(2^{|?|}\)的暴力非常好做. 观察到\(min(|1|,| ...

  4. 「BalkanOI 2018 Day1」Election

    「BalkanOI 2018 Day1」Election 记C为1,T为-1,\(sum[i]\)为\(i\)点的前缀和. 对于询问\([l,r]\),分两步计算答案. 要求所有点的\(sum[i]- ...

  5. 「BalkanOI 2018 Day1」Minmaxtree

    「BalkanOI 2018 Day1」Minmaxtree 每个点都有一个最大和最小权值的限制. 然后每一个权值的限制都必须要取到. 每个点显然可以直接让他取到最大或最小权值. 可以想到每个点匹配一 ...

  6. LOJ#2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On

    题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有 N×M 个这样 ...

  7. 2018.10.14 loj#6003. 「网络流 24 题」魔术球(最大流)

    传送门 网络流好题. 这道题可以动态建图. 不难想到把每个球iii都拆点成i1i_1i1​和i2i_2i2​,每次连边(s,i1),(i2,t)(s,i_1),(i_2,t)(s,i1​),(i2​, ...

  8. LOJ2321. 「清华集训 2017」无限之环【费用流】

    LINK 很好的一道网络里题 首先想插头DP的还是出门左转10分代码吧 然后考虑怎么网络流 首先要保证没有漏水 也就是说每个接口一定要有对应的接口 那么发现每个点只有可能和上下左右四个点产生联通关系 ...

  9. 【LOJ】#3032. 「JOISC 2019 Day1」馕

    LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...

随机推荐

  1. MySQL主从复制与Atlas读写分离

    配置主从复制 1. 增加主从配置 # 主库配置文件 server-id = 1 log-bin = /var/lib/mysql/mysql-bin expire_logs_days = 10 ski ...

  2. uniapp封装小程序雷达图组件实现

    效果图: view <canvas id="radar-canvas" class="radar-canvas" type="2d"& ...

  3. 异步编程之APM

    一.APM概述 APM即异步编程模型的简写(Asynchronous Programming Model),我们平时经常会遇到类似BeginXXX和EndXXX的方法,我们在使用这些方法的时候,其实就 ...

  4. WPF---数据绑定之Xml数据源(四)

    一.场景 现在外部有一xml文件,我们想将该xml文件中的内容绑定到ListView中,该如何实现? 二.实现 xml文件的内容如下: <?xml version="1.0" ...

  5. filter打包区分环境

    项目目录结构: 父pom: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...

  6. eclipse性能调优的一次记录

    最近因为学习原因,eclipse中插件越来越多,造成eclipse一次次假死,着实很影响工作效率和心情,有时正是兴起,但是造成短片很令人生气,如果eclipse卡顿或者假死,在电脑配置较不错的情况下, ...

  7. ABC类IP地址

    A类IP地址一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位 必须是"0", 地址范围从1.0.0.0 到126.0.0.0.可用的A类网络有126个,每个 ...

  8. String与Int类型的转换

    http://blog.sina.com.cn/s/blog_4f9d6b1001000bfo.html int -> String int i=12345; String s="&q ...

  9. sychronized

    说一下 synchronized 底层实现原理? synchronized可以保证方法或者代码块在运行时, 同一时刻只有一个方法可以进入到临界区, 同时它还可以保证共享变量的内存可见性. Java中每 ...

  10. java发送短信开发,第三方接口方法

    必备的三个jar包Maven有自己去下: commons-logging commons-logging 1.1 commons-httpclient commons-httpclient 3.1 c ...