思路: 点分治

提交:5次

题解:

刚开始用排序+双指针写的,但是调了一晚上,总是有两个点过不了,第二天发现原因是排序时的\(cmp\)函数写错了:如果对于路径长度相同的,我们从小往大按边数排序,当双指针出现\(==k\)时,即我们应先左移右指针,否则答案可能会变劣(仔细想一想);若反着排序,应该先右移左指针。

#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
template<class I> inline I g(I& x) { x=0; register I f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=2e5+10,Inf=1e+9;
int n,K,cnt,sum,rt,tot,ans=N; bool vis[N];
int vr[N<<1],nxt[N<<1],fir[N],w[N<<1],sz[N],d[N],f[N],b[N],mx[N],mem[N];
inline void add(int u,int v,int ww) {
vr[++cnt]=v,nxt[cnt]=fir[u],w[cnt]=ww,fir[u]=cnt;
vr[++cnt]=u,nxt[cnt]=fir[v],w[cnt]=ww,fir[v]=cnt;
}
inline void getsz(int u,int fa) { sz[u]=1,mx[u]=0;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
getsz(v,u),sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
} mx[u]=max(mx[u],sum-sz[u]);
if(mx[u]<mx[rt]) rt=u;
}
inline void getdis(int u,int fa) { mem[++tot]=u;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
d[v]=d[u]+w[i],f[v]=f[u]+1,b[v]=b[u];
if(d[v]<=K) getdis(v,u);
}
}
inline bool cmp(const int& a,const int& b) {
return d[a]<d[b]||(d[a]==d[b]&&f[a]>f[b]);
}
inline void solve(int u,int fa) {
tot=0,vis[u]=true; mem[++tot]=u,d[u]=f[u]=0,b[u]=u;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
d[v]=w[i],f[v]=1,b[v]=v; getdis(v,u);
} sort(mem+1,mem+tot+1,cmp);
// for(R i=1;i<=tot;++i) cout<<mem[i]<<" "; cout<<endl;
R l=1,r=tot; while(l<r) {
if(d[mem[l]]+d[mem[r]]>K) --r;
else if(d[mem[l]]+d[mem[r]]<K) ++l;
else if(b[mem[l]]==b[mem[r]]) {
// if(d[mem[r]]==d[mem[r-1]]) --r;
// else ++l;
if(d[mem[l]]==d[mem[l+1]]) ++l;
else --r;
} else {
ans=min(ans,f[mem[l]]+f[mem[r]]);
// if(d[mem[r]]==d[mem[r-1]]) --r;
// else ++l;
if(d[mem[l]]==d[mem[l+1]]) ++l;
else --r;
}
} for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
sum=sz[v],rt=0,mx[rt]=Inf;
getsz(v,u); getsz(rt,-1); solve(rt,u);
}
}
inline void main() {
g(n),g(K); for(R i=1,u,v,w;i<n;++i) g(u),g(v),g(w),++u,++v,add(u,v,w);
sum=n,mx[0]=Inf; getsz(1,-1),getsz(rt,-1); solve(rt,-1);
if(ans==N) return (void) puts("-1"); printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}

但是上面的方法比较慢,多一个\(log\)。

于是还是类比点分治板子的思想,对于一颗子树,与之前的子树做贡献。我们可以开一个类似桶的数组记录长度为\(len\)的路径有没有出现过,同时对应记录长度为\(len\)的路径对应的最小边数。每求出来一颗子树的信息就扫一遍。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
template<class I> inline I g(I& x) { x=0; register I f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=2e5+10,M=1e6+10,Inf=0x3f3f3f3f;
int n,K,cnt,sum,rt,tot,ans=N,SZ; bool vis[N],mem[M];
int vr[N<<1],nxt[N<<1],fir[N],w[N<<1],sz[N],d[N],f[M],s[N],mx[N],buf[N],l[N],dis[N];
inline void add(int u,int v,int ww) {
vr[++cnt]=v,nxt[cnt]=fir[u],w[cnt]=ww,fir[u]=cnt;
vr[++cnt]=u,nxt[cnt]=fir[v],w[cnt]=ww,fir[v]=cnt;
}
inline void getsz(int u,int fa) { sz[u]=1,mx[u]=0;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
getsz(v,u),sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
} mx[u]=max(mx[u],sum-sz[u]);
if(mx[u]<mx[rt]) rt=u;
}
inline void getdis(int u,int fa) {
dis[++tot]=d[u],l[tot]=s[u];
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
d[v]=d[u]+w[i],s[v]=s[u]+1;
if(d[v]<=K) getdis(v,u);
}
}
//inline bool cmp(const int& a,const int& b) {
// return d[a]<d[b]||(d[a]==d[b]&&f[a]>f[b]);
//}
//inline void solve(int u,int fa) {
// tot=0,vis[u]=true; mem[++tot]=u,d[u]=f[u]=0,b[u]=u;
// for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
// if(v==fa||vis[v]) continue;
// d[v]=w[i],f[v]=1,b[v]=v; getdis(v,u);
// } sort(mem+1,mem+tot+1,cmp);
//// for(R i=1;i<=tot;++i) cout<<mem[i]<<" "; cout<<endl;
// R l=1,r=tot; while(l<r) {
// if(d[mem[l]]+d[mem[r]]>K) --r;
// else if(d[mem[l]]+d[mem[r]]<K) ++l;
// else if(b[mem[l]]==b[mem[r]]) {
//// if(d[mem[r]]==d[mem[r-1]]) --r;
//// else ++l;
// if(d[mem[l]]==d[mem[l+1]]) ++l;
// else --r;
// } else {
// ans=min(ans,f[mem[l]]+f[mem[r]]);
//// if(d[mem[r]]==d[mem[r-1]]) --r;
//// else ++l;
// if(d[mem[l]]==d[mem[l+1]]) ++l;
// else --r;
// }
// } for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
// if(v==fa||vis[v]) continue;
// sum=sz[v],rt=0,mx[rt]=Inf;
// getsz(v,u); getsz(rt,-1); solve(rt,u);
// }
//}
inline void solve(int u,int fa) { tot=0; vis[u]=true;
buf[++SZ]=0,mem[0]=true,d[u]=s[u]=0,f[0]=0;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(vis[v]||v==fa) continue;
d[v]=w[i],s[v]=1; getdis(v,u);
for(R i=1;i<=tot;++i) if(K>=dis[i]&&mem[K-dis[i]])
ans=min(ans,f[K-dis[i]]+l[i]);
for(R i=1;i<=tot;++i) {
if(!mem[dis[i]]) buf[++SZ]=dis[i],mem[dis[i]]=true;
f[dis[i]]=min(f[dis[i]],l[i]);
} tot=0;
} while(SZ) mem[buf[SZ]]=false,f[buf[SZ]]=Inf,--SZ;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(v==fa||vis[v]) continue;
sum=sz[v],rt=0,mx[rt]=Inf;
getsz(v,u),getsz(rt,-1); solve(rt,u);
}
}
inline void main() {
memset(f,0x3f,sizeof(f)); g(n),g(K);
for(R i=1,u,v,w;i<n;++i) g(u),g(v),g(w),++u,++v,add(u,v,w);
sum=n,mx[0]=Inf; getsz(1,-1),getsz(rt,-1); solve(rt,-1);
if(ans==N) return (void) puts("-1"); printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}

还有最近老犯一个错误,数组名老弄重导致算错。。。必须给予重视。。


2019.08.31

69

P4149 [IOI2011]Race 点分治的更多相关文章

  1. 洛谷$P4149\ [IOI2011]\ Race$ 点分治

    正解:点分治 解题报告: 传送门$QwQ$ 昂先不考虑关于那个长度的限制考虑怎么做? 就开个桶,记录所有边的取值,每次加入边的时候查下是否可行就成$QwQ$ 然后现在考虑加入这个长度的限制?就考虑把这 ...

  2. 模板—点分治B(合并子树)(洛谷P4149 [IOI2011]Race)

    洛谷P4149 [IOI2011]Race 点分治作用(目前只知道这个): 求一棵树上满足条件的节点二元组(u,v)个数,比较典型的是求dis(u,v)(dis表示距离)满足条件的(u,v)个数. 算 ...

  3. BZOJ 2599: [IOI2011]Race( 点分治 )

    数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新 ...

  4. [IOI2011]Race 点分治

    [IOI2011]Race LG传送门 点分治板子题. 直接点分治统计,统计的时候开个桶维护下就好了. 注(tiao)意(le)细(hen)节(jiu). #include<cstdio> ...

  5. [bzoj2599][IOI2011]Race——点分治

    Brief Description 给定一棵带权树,你需要找到一个点对,他们之间的距离为k,且路径中间的边的个数最少. Algorithm Analyse 我们考虑点分治. 对于子树,我们递归处理,所 ...

  6. 洛谷 4149 [IOI2011]Race——点分治

    题目:https://www.luogu.org/problemnew/show/P4149 第一道点分治! 点分治大约是每次找重心,以重心为根做一遍树形dp:然后对于该根的每个孩子,递归下去.递归之 ...

  7. 洛谷P4149 [IOI2011]Race(点分治)

    题目描述 给一棵树,每条边有权.求一条简单路径,权值和等于 KK ,且边的数量最小. 输入输出格式 输入格式:   第一行:两个整数 n,kn,k . 第二至 nn 行:每行三个整数,表示一条无向边的 ...

  8. P4149 [IOI2011]Race

    对于这道题,明显是点分治,权值等于k,可以用桶统计树上路径(但注意要清空); 对于每颗子树,先与之前的子树拼k,再更新桶,维护t["len"]最小边数; #include < ...

  9. bzoj2599/luogu4149 [IOI2011]Race (点分治)

    点分治.WA了一万年. 重点就是统计答案的方法 做法一(洛谷AC bzojWA 自测WA): 做点x时记到x距离为k的边数最小值为dis[k],然后对每一对有值的dis[i]和dis[K-i],给an ...

随机推荐

  1. pandas数据结构之基础运算笔记

    import pandas as pd import numpy as np s = pd.Series([1,3,5,6,8],index=list('acefh')) s.index # 读取行索 ...

  2. RHadoop: REDUCE capability required is more than the supported max container capability in the cluster

    I have not used RHadoop. However I've had a very similar problem on my cluster, and this problem see ...

  3. 创客课堂——Scratch实例演示

    大家好,这里是蓝精灵创客公益课堂,我是蓝老师. 前两期我们认识了Scratch的界面和菜单功能,本期我们就可以根据提示的步骤,学习一些Scratch的基本操作. 下面就开始今天学习内容 一.开始移动 ...

  4. Scratch2.0教材(9)——合体大变身

    教材说明 ——————— 1.本教材共96节课,适用于3-5年级.40人.40分钟的课堂: 2.初期我会把每节课的代码控制在10行以内,后期再逐渐增加: 3.欢迎提意见. 课程摘要 ——————— [ ...

  5. 使用QFileInfo类获取文件信息(文件的所有权和权限检查在默认情况下是被禁用的。要使能这个功能 extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;)

    QFileInfo类为我们提供了系统无关的文件信息,包括文件的名字和在文件系统中位置,文件的访问权限,是否是目录或符合链接,等等.并且,通过这个类,可以修改文件的大小和最后修改.读取时间.同时,QFi ...

  6. 奇妙的算法【9】YC每个小孩的糖果数,找公约数,最少硬币数

    1,每个小孩的糖果数量是多少 有p个小孩,c个糖果,刚开始第1个小孩发一个糖果,第2个小孩发两个糖果,第p个小孩发p个糖果,如果糖果没有发完,就接着[注意]第1个小孩发p+1个糖果.....第p个小孩 ...

  7. 在ASP.NET Core中实现自动注入、批量注入

    我们在使用AddScoped.AddTransient.AddSingleton这类方法的时候很是麻烦.我们每增加一个接口以及其实现的时候,是不是需要在这里硬编码注册一行代码呢?项目小还好,但当我们的 ...

  8. pytorch中使用多显卡训练以及训练时报错:expect more than 1 value per channel when training, got input size..

    pytorch在训练中使用多卡: conf.device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu&quo ...

  9. Linux Centos7配置ftp服务器

    一.安装 1.安装 yum install  -y vsftpd 2.设置开机启动 systemctl enable vsftpd.service 3.启动 systemctl start vsftp ...

  10. Invariant Violation: requireNativeComponent: "RNCWKWebView" was not found in the UIManager.

    react-native  0.60以上版本安装第三方库的时候会autolink  出现这个问题是 我安装 react-native-webview 之后运行 ios出现的,这是因为ios 没有自动安 ...