bzoj2599 [ IOI2011] -- 点分治

令ans[i]表示权值和等于k的路径条数,然后点分治就可以了。

具体看代码。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 #define N 200010
 8 #define INF 2147483647
 9 inline int Min(int x,int y){return x<y?x:y;}
10 inline int Max(int x,int y){return x<y?y:x;}
11 vector<int>g[N];
12 vector<int>w[N];
13 struct Node{
14     int x,y;
15     Node(){}
16     Node(int x,int y):x(x),y(y){}
17 }a[N];
18 int i,j,k,n,m,f[N],s[N],Sum,Rt,Ans[N],x,y,z,l;
19 bool b[N];
20 inline void Add(int x,int y,int z){g[x].push_back(y);w[x].push_back(z);}
21 inline void Get_root(int x,int y){
22     s[x]=1;f[x]=0;
23     for(int i=0;i<g[x].size();i++)
24     if(!b[g[x][i]]&&g[x][i]!=y){
25         Get_root(g[x][i],x);
26         s[x]+=s[g[x][i]];
27         f[x]=Max(f[x],s[g[x][i]]);
28     }
29     f[x]=Max(f[x],Sum-s[x]);
30     if(f[x]<f[Rt])Rt=x;
31 }
32 inline void Dfs(int x,int y,int z,int Sum){
33     a[++l]=Node(z,Sum);
34     for(int i=0;i<g[x].size();i++)
35     if(!b[g[x][i]]&&g[x][i]!=y)Dfs(g[x][i],x,z+w[x][i],Sum+1);
36 }
37 inline bool Cmp(Node a,Node b){return a.x<b.x;}
38 inline void Calc(int x,int y,int z){
39     l=0;if(y==1)Dfs(x,0,z,0);else Dfs(x,0,z,1);
40     sort(a+1,a+l+1,Cmp);
41     for(int i=1;i<=l;i++){
42         while(a[l].x+a[i].x>k&&l>i)l--;
43         for(int p=l;a[p].x+a[i].x==k;p--)Ans[a[p].y+a[i].y]+=y;
44     }
45 }
46 inline void Solve(int x){
47     b[x]=1;Calc(x,1,0);
48     for(int i=0;i<g[x].size();i++)
49     if(!b[g[x][i]]){
50         Calc(g[x][i],-1,w[x][i]);
51         Sum=s[g[x][i]];f[Rt=0]=n+1;Get_root(g[x][i],0);
52         Solve(Rt);
53     }
54 }
55 int main(){
56     scanf("%d%d",&n,&k);
57     for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),Add(x+1,y+1,z),Add(y+1,x+1,z);
58     Sum=n;f[Rt=0]=n+1;Get_root(1,0);
59     Solve(Rt);
60     for(i=1;i<=n;i++)
61     if(Ans[i]>0){printf("%d\n",i);return 0;}
62     puts("-1");
63     return 0;
64 }

bzoj2599

时间: 2024-08-08 03:28:49

bzoj2599 [ IOI2011] -- 点分治的相关文章

bzoj2599: [IOI2011]Race(点分治)

写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是一样的.先找重心,然后先从重心开始求距离dis和边数num,更新ans,再从重心的儿子开始求得dis和num,减去这部分答案 因为这部分的答案中,从重心开始的两条链有重叠部分,所以要剪掉 基本算是模板题,但是减去儿子的答案的那部分还有双指针那里调了好久,所以还不算特别熟练.. PS跑了27秒慢到飞起

[BZOJ2599][Race][IOI2011]点分治

这是为了真正去学一下点分治..然后看了迪克李的ppt 又是一道写(改)了很久的题..终于ac了 1354799 orzliyicheng 2599 Accepted 31936 kb 23584 ms C++/Edit 2218 B 2016-03-27 15:55:17 不算快呢..具体实现是看的hzwer的blog,然而迪克李的ppt已经将想法讲得很清楚了 uoj文件里有,就懒得贴题解了 刚刚写完的时候,一个极限数据要跑60sec,我也是醉了..主要原因有: 1.清空数组的时候竟然跑了n遍f

【点分治】【哈希表】bzoj2599 [IOI2011]Race

给nlog2n随便过的跪了,不得已弄了个哈希表伪装成nlogn(当然随便卡,好孩子不要学)…… 不过为啥哈希表的大小开小点就RE啊……?必须得超过数据范围一大截才行……谜 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int f,c; inline void R(int &x){ c=0;f=1; for(;c<'0'||c>'9';c=getc

bzoj1758 [Wc2010]重建计划 &amp; bzoj2599 [IOI2011]Race

两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调整二分上界.假设一棵树树根为x,要求就是经过树根x的最大答案,不经过树根x的可以递归求解.假设B[i]为当前做到的一颗x的子树中的点到x的距离为i的最大权值,A[i]为之前已经做过的所有子数中的点到x的距离为i的最大权值(这里的权值是Σv(e)-i*avgvalue),那么对于当前子树的一个距离i,

[BZOJ2599][IOI2011]Race

试题描述 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 输入 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) 输出 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 输入示例 4 3 0 1 1 1 2 2 1 3 4 输出示例 2 数据规模及约定 见“试题描述” 题解 点分治裸题.我还调了半天TAT...好久没写什么都忘了... 每次找子树的中心往下递

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什

【BZOJ2599】[IOI2011]Race 树的点分治

[BZOJ2599][IOI2011]Race Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 题解:本题大

【BZOJ2599】[IOI2011]Race【点分治】

[题目链接] 点分治. 考虑经过点x的路径,对于x,用类似TreeDP的方法,记录no[d],表示路径长度为d时经过边最少的点的编号. 对于已经走过的子树,更新no.对于当前子树,遍历到一个点v,用depth[no[k - dis[v]]] + depth[v]更新答案. 注意给no清零时,用dfs姿势清零,这样做是O(n)的.如果直接用for或者memset,这样做是O(k)的,会TLE. /* Telekinetic Forest Guard */ #include <cstdio> #i

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

数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新CNT数组和答案. ------------------------------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typ