博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
#20. 暗之连锁——Yucai OJ第16次测试
阅读量:5344 次
发布时间:2019-06-15

本文共 3409 字,大约阅读时间需要 11 分钟。

问题描述

在的古老传说中,暗之连锁是人类内心黑暗的产物。人们又称它为 Dark。一代又一代 的武士们都试图打倒它,同时作为自然科学先驱 者和剑道高手的 ZYS也不例外。 ZYS发现,Dark 实际上可以抽象为由 N 个 点、M+NM+N−1 条边构成的无向图,图中的边分为两 类,分别称为主要边和附加边。其中 NN–1 条为主 要边,M 条为附加边,并且任意两点之间必定存在一条仅由主要边构成的简单 路径。 以 ZYS的能力,最多可以斩断 Dark 的一条主要边和一条附加边。最初, Dark 处于引诱模式,所有的附加边都处于无敌状态,但主要边可以被斩断。在 一条主要边被斩断后,Dark 立刻进入认真模式,剩余的主要边处于无敌状态, 而附加边可以被斩断。如果在斩断一条主要边和一条附加边后,构成 Dark 的 N 个点被分成不连通的两部分,那么 Dark 会强制进入消减模式并最终灭亡。 ZYS想要知道,一共有多少种方案可以击败 Dark。注意,就算斩断一条 主要边之后,Dark 已经分为两截,你也需要再任意斩断一条附加边。

输入格式

第一行包含两个整数 N 和 M 。 之后 NN–1 行,每行包括两个整数 A 和 B ,表示 A 和 B 之间有一条主要边。 之后 M 行以同样的格式给出附加边。

输出格式

输出一个整数表示答案。

样例输入

4 1 1 2 2 3 1 4 3 4

样例输出

3

数据范围

对于 2020% 的数据,N100M100 N≤100,M≤100 。

对于 100100% 的数据,N100000M200000 N≤100000,M≤200000 。数据保证答案不超过 31 231–1 。

时空限制

2S/512MB

题解

第一道树上差分。差分,就是在大都市meg里面学到的那种开头减,结尾加,前缀和来看状态的方法,例题还有一道借教室(不是换教室!)。在树上差分可以表示出两点之间的路径,只要在两端点均+1,LCA-2,最后用dfs统计和就可以了。过去学的LCA有朴素、ST、tarjan离线、在线、倍增,这次用的是tarjan,大概也是我最熟练的一种:两次头插法分别加双向边和存问题,还要用到并查集。差分、LCA、dfs三个步骤结束后得到每条实边被x条虚边覆盖,x=0的实边对答案有m的贡献,x=1的实边对答案有1的贡献。学长们出的加强版需要删掉不止一条虚边一条实边,如果边有富裕的话就会产生一个组合数的贡献,计算组合数大概是ad学长上次讲到的那些方法,数据小递推就可以了。

(摘自神犇moyiii“暗之链锁”题解)

1 #include
2 using namespace std; 3 const int sj=200010; 4 int n,m,po[sj/2],a1,a2,jg,h[sj],l[sj],ans[sj],e,f; 5 int fa[sj/2],zx[sj/2],re[sj/2],dep[sj/2]; 6 struct B{ 7 int u,v,ne; 8 }b[sj]; 9 struct Q{ 10 int u,v,ne,num; 11 }q[sj*2]; 12 void add(int x,int y){ 13 b[e].u=x; 14 b[e].v=y; 15 b[e].ne=h[x]; 16 h[x]=e++; 17 } 18 int find(int x){ 19 if(fa[x]==-1){ 20 return x; 21 } 22 fa[x]=find(fa[x]); 23 return fa[x]; 24 } 25 void hb(int x,int y){ 26 x=find(x); 27 y=find(y); 28 if(x!=y){ 29 fa[x]=y; 30 } 31 return ; 32 } 33 void lca(int x){ 34 zx[x]=x; 35 re[x]=1; 36 for(int i=h[x];i!=-1;i=b[i].ne){ 37 if(!re[b[i].v]){ 38 lca(b[i].v); 39 hb(x,b[i].v); 40 zx[find(b[i].v)]=x; 41 } 42 } 43 for(int i=l[x];i!=-1;i=q[i].ne){ 44 if(re[q[i].v]){ 45 ans[q[i].num]=zx[find(q[i].v)]; 46 } 47 } 48 return ; 49 } 50 void adq(int x,int y,int z){ 51 q[f].u=x; 52 q[f].v=y; 53 q[f].num=z; 54 q[f].ne=l[x]; 55 l[x]=f++; 56 return ; 57 } 58 void dfs(int x){ 59 for(int i=h[x];i!=-1;i=b[i].ne){ 60 if(!re[b[i].v]){ 61 re[b[i].v]=1; 62 dep[b[i].v]=dep[x]+1; 63 dfs(b[i].v); 64 po[x]+=po[b[i].v]; 65 } 66 } 67 return ; 68 } 69 int main(){ 70 cin>>n>>m; 71 memset(h,-1,sizeof(h)); 72 memset(fa,-1,sizeof(fa)); 73 memset(l,-1,sizeof(l)); 74 for(int i=1;i
>a1>>a2; 76 add(a1,a2); 77 add(a2,a1); 78 } 79 for(int i=1;i<=m;i++){ 80 cin>>a1>>a2; 81 adq(a1,a2,i); 82 adq(a2,a1,i); 83 po[a1]++; 84 po[a2]++; 85 } 86 lca(1); 87 for(int i=1;i<=m;i++){ 88 po[ans[i]]-=2; 89 } 90 memset(re,0,sizeof(re)); 91 re[1]=1; 92 dep[1]=1; 93 dfs(1); 94 for(int i=0;i
dep[b[i].u]){103 if(po[b[i].v]==0){104 jg+=m;105 }else if(po[b[i].v]==1){106 jg++;107 }108 }109 }110 cout<
<
标程

 

转载于:https://www.cnblogs.com/VOCAOID/p/9555309.html

你可能感兴趣的文章
20145205 《信息安全系统设计基础》第14周学习总结
查看>>
6)添加一个窗口的图标
查看>>
POJ - 1422 Air Raid 二分图最大匹配
查看>>
Road Map
查看>>
正则替换中的一个Bug
查看>>
HI3531uboot开机画面 分类: arm-linux-Ubunt...
查看>>
制作U盘启动CDLinux 分类: 生活百科 ...
查看>>
strcpy函数里的小九九
查看>>
搭建ssm过程中遇到的问题集
查看>>
OpenLayers绘制图形
查看>>
tp5集合h5 wap和公众号支付
查看>>
Flutter学习笔记(一)
查看>>
iOS10 国行iPhone联网权限问题处理
查看>>
洛谷 P1991 无线通讯网
查看>>
[HIHO1184]连通性二·边的双连通分量(双连通分量)
查看>>
Codeforces Round #178 (Div. 2) B. Shaass and Bookshelf 【动态规划】0-1背包
查看>>
SparkStreaming 源码分析
查看>>
【算法】—— 随机音乐的播放算法
查看>>
mysql asyn 示例
查看>>
DataGrid 点击 获取 行 ID
查看>>