正题

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


题目大意

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

输出方案

1≤n≤500,1≤m≤105,∑∣S∣≤1061\leq n\leq 500,1\leq m\leq10^5,\sum |S|\leq 10^61≤n≤500,1≤m≤105,∑∣S∣≤106


解题思路

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

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

先原点向每一个叶子连流量为1的边,设sizxsiz_xsizx​表示xxx的子树中有多少个叶子那么xxx向faxfa_xfax​连接流量为sizx−1siz_x-1sizx​−1的边,然后根向汇点连流量为siz1siz_1siz1​的边。

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


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. 【LOJ】#3030. 「JOISC 2019 Day1」考试

    LOJ#3030. 「JOISC 2019 Day1」考试 看起来求一个奇怪图形(两条和坐标轴平行的线被切掉了一个角)内包括的点个数 too naive! 首先熟练的转化求不被这个图形包含的个数 -- ...

  2. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

  3. [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)

    [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 -- 接着他们发现自己收 ...

  4. 「JOISC 2014 Day1」巴士走读

    「JOISC 2014 Day1」巴士走读 题解部分: (如果不怎么喜欢看推导的人可以直接看下面的关键部分,在段尾会有标注(或者看完定义直接看代码)) 本题让我们求到达点n需要最晚何时到达点1,我们可 ...

  5. [LOJ#2329]「清华集训 2017」我的生命已如风中残烛

    [LOJ#2329]「清华集训 2017」我的生命已如风中残烛 试题描述 九条可怜是一个贪玩的女孩子. 这天她在一堵墙钉了 \(n\) 个钉子,第 \(i\) 个钉子的坐标是 \((x_i,y_i)\ ...

  6. LOJ#2833 「JOISC 2018 Day 1」帐篷 dp

    题目描述 译自 JOISC 2018 Day1 T3「テント / Tents」 JOI 君经营着一座露营地.露营地被划分为 H 行 W 列的矩阵,各行平行于东西方向,而各列平行于南北方向.从北向南数第 ...

  7. loj #6226. 「网络流 24 题」骑士共存问题

    #6226. 「网络流 24 题」骑士共存问题 题目描述 在一个 n×n\text{n} \times \text{n}n×n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些 ...

  8. [LOJ #521]「LibreOJ β Round #3」绯色 IOI(抵达)(结论)

    #521. 「LibreOJ β Round #3」绯色 IOI(抵达) description solution 因为点的庇护所不能为自身,题目背景在树上,有结论一定是两个相邻点互为庇护所 所以树一 ...

  9. loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分...

    $ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinob ...

最新文章

  1. C++ 下面的AIDL
  2. java16位字符串压缩成8位_在8位UART上发送16位值
  3. python随机生成字母和数字的混合字符串_用python生成数字、字母和特殊字符混合的字符串...
  4. iPhone 的 Push(推送通知)功能原理浅析
  5. Android之在Activity中动态得到Adapter类中数据
  6. 【Leetcode | 9】217. 存在重复元素
  7. Delphi WebBrowser控件的使用
  8. 别翻了,常见的锁策略就在这里了~
  9. HTTP,FTP,SMTP错误码
  10. DSP28335 Flash烧写
  11. python 每周第一天和最后一天
  12. MAX30102 血氧调试笔记
  13. 数据安全治理方法导论
  14. Excel 批量删除空白行,你用了 2 小时,同事 3 分钟就搞定了
  15. Nginx Passenger 性能调优
  16. 笔记本闪屏是怎么回事呢?笔记本闪屏三个原因介绍
  17. 手把手系列之三十二——手把手教你做香果魔芋
  18. windows不能同时连接有线和无线
  19. Android系统(手机平板)根目录详解
  20. 2021年中国互联网网民规模及互联网普及率情况:网民总体规模持续增长,城乡地区互联网普及率差异减小[图]

热门文章

  1. java web容器_Java Web容器安全
  2. c语言逆序数输三个数,C语言求助!一个三位数的逆序数,总是编不对
  3. python distplot 图_Python可视化23 |seaborn.distplot公司单变量分布图(直方图|核密度图),23seaborndistplot...
  4. pc模式 华为mate30_华为mate30与电脑连不上怎么回事
  5. 机器学习之数据预处理——数据清洗(缺失值、异常值和重复值的处理)
  6. 线程与线程池(一条龙详解)
  7. AVL树的旋转与插入(C语言)
  8. AcWing 126. 最大的和
  9. java中vi是什么意思_java中的public void是什么意思?
  10. 网络编程-HTTPS协议的实现原理