[bzoj 1468] Tree

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1468

Tree

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1517  Solved: 812
[Submit][Status][Discuss]

Description

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

Input

N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

Output

一行,有多少对点之间的距离小于等于k

Sample Input

7
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10

Sample Output

5

点分治裸题,和poj上的不一样,不一样!!!

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define gc() getchar()
  6 #define max(a,b) ((a)>(b)?(a):(b))
  7 using namespace std;
  8 int read()
  9 {
 10     int rt=0,fl=1;char ch=gc();
 11     while(!isdigit(ch)){if(ch==‘-‘)fl=-1;ch=gc();}
 12     while(isdigit(ch)){rt=rt*10+ch-‘0‘;ch=gc();}
 13     return rt*fl;
 14 }
 15
 16 const int MAXN = 100005;
 17
 18 int h[MAXN],nx[MAXN<<1],to[MAXN<<1],val[MAXN<<1],cnt;
 19 int son[MAXN],f[MAXN],d[MAXN],deep[MAXN],root,sum,n,k,ans;
 20 bool vis[MAXN];
 21
 22 void add_edge(int _u,int _v,int _c)
 23 {
 24     to[++cnt]=_v;
 25     nx[cnt]=h[_u];
 26     h[_u]=cnt;
 27     val[cnt]=_c;
 28 }
 29
 30 void link(int _u,int _v,int _c)
 31 {
 32     add_edge(_u,_v,_c);
 33     add_edge(_v,_u,_c);
 34 }
 35
 36 void clear()
 37 {
 38     memset(h,0,sizeof(h));
 39     memset(vis,0,sizeof(vis));
 40     cnt=0;
 41     ans = root = 0;
 42 }
 43
 44 void getRoot(int rt,int fa)
 45 {
 46     son[rt]=1;
 47     f[rt]=0;
 48     for(int i=h[rt];i;i=nx[i])
 49     {
 50         if(to[i]==fa || vis[to[i]]==1)continue;
 51         getRoot(to[i],rt);
 52         son[rt] += son[to[i]];
 53         f[rt] = max(f[rt],son[to[i]]);
 54     }
 55     f[rt] = max(f[rt],sum - son[rt]);
 56     if(f[rt] < f[root]) root = rt;
 57 }
 58
 59 void getDeep(int rt,int fa)
 60 {
 61     deep[++deep[0]] = d[rt];
 62     for(int i=h[rt];i;i=nx[i])
 63     {
 64         if(to[i]==fa || vis[to[i]]==1)continue;
 65         d[to[i]] = d[rt] + val[i];
 66         getDeep(to[i],rt);
 67     }
 68 }
 69
 70 int cal(int x,int now)
 71 {
 72     d[x] = now;
 73     deep[0] = 0;
 74     getDeep(x,0);
 75     sort(deep+1,deep+deep[0]+1);
 76     int t = 0,l,r;
 77     for(l=1,r=deep[0];l<r;)
 78     {
 79         if(deep[l] + deep[r] <= k)
 80         {
 81             t+=r-l;
 82             l++;
 83         }
 84         else r--;
 85     }
 86     return t;
 87 }
 88 void work(int rt)
 89 {
 90     ans += cal(rt,0);
 91     vis[rt] = 1;
 92     for(int i=h[rt];i;i=nx[i])
 93     {
 94         if(vis[to[i]]==1) continue;
 95         ans -= cal(to[i],val[i]);
 96         sum = son[to[i]];
 97         root = 0;
 98         getRoot(to[i],root);
 99         work(root);
100     }
101 }
102 int main()
103 {
104     n=read();
105     for(int i=1;i<n;i++)
106     {
107         int a,b,c;
108         a=read();
109         b=read();
110         c=read();
111         link(a,b,c);
112         }
113     k=read();
114         sum = n;
115         f[0] = 0x3f3f3f3f;
116         getRoot(1,0);
117         work(root);
118         printf("%d\n",ans);
119     return 0;
120 }
时间: 2024-10-24 15:27:22

[bzoj 1468] Tree的相关文章

bzoj 1468 Tree(点分治模板)

1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1527  Solved: 818[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k Sample Input 7 1 6 13 6

BZOJ.1468.Tree(点分治)

题目链接 BZOJ1468 POJ1741 题意: 计算树上距离<=K的点对数 我们知道树上一条路径要么经过根节点,要么在同一棵子树中. 于是对一个点x我们可以这样统计: 计算出所有点到它的距离dep[],排序后可以O(n)求得<=K的点对数量. 但画个图后我们可以发现,对于在同一棵子树中的路径被重复计算过了.于是我们Ans-=Calc(v),减去一棵子树中的路径答案,但是这并不是之前x到它们的路径,于是给v的dep[]设一个初始值为w(x->v路径权值). 这样x的答案就计算完了,将这

BZOJ 1468 Tree 【模板】树上点分治

1 #include<cstdio> 2 #include<algorithm> 3 #define N 50010 4 #define M 500010 5 #define rg register 6 #define LL long long 7 using namespace std; 8 int n,m,cnt,root,tot,totnow,totbf; 9 int last[N],size[N],mxsize[N],dep[N],tmp[N],mg[N]; 10 LL a

点分治专题——bzoj 1468 &amp;bzoj 2152 题解

[前言]最近一直在忙着学算法,但是效果似乎不是很好.前段时间的树剖也快忘了= =.树套树没熟练,就开始写主席树了= =.更别说本身就不是很懂的莫比乌斯反演了.~~决定好好复习一下. [点分治的作用]套用SYC大神的话说是:用来解决树上路径点权统计问题. [大致流程] ①找出这颗树的重心. ②统计经过这个重心的答案 ③用重心把树割开 ④对每个"小树"做同样的事 [Q1--重心]其实找重心再进行计算只是为了不被卡链.什么是重心?就是当前树中的一个点K,使得MAX(SON[K])最小.SON

【BZOJ】1468: Tree(点分治)

http://www.lydsy.com/JudgeOnline/problem.php?id=1468 分治真是一门高大上的东西... 好神... 树分治最好资料是:qzc的<分治算法在树的路径问题中的应用> 我来说说自己的理解: 点分=找重心+分治 找重心尤为重要,因为这关系到时间复杂度. 对于递归式 $$T(n)=aT(n/b)+O(D(n))$$ 这类递归式,如果能保证每一层都是$O(D(n))$,那么时间复杂度会大大减小.(详见算导第三章和第四章) 对于一棵树,如果我们在找到重心后,

【BZOJ 1468】Tree 点分治

点分治$O(nlogn)$ 坚持到月考结束后新校就剩下我一个OIer,其他人早已停课了,老师估计懒得为我一个人开机房门,让我跟班主任说了一声,今晚就回到了老校,开始了自己都没有想到会来的这么早的停课生活. 所以先水一道点分治 #include<cstdio> #include<algorithm> #define read(x) x=getint() #define N 40003 #define max(a,b) (a)>(b)?(a):(b) using namespac

【BZOJ】1468: Tree(POJ1741)

[题意]给定带边权树,求两点距离<=k的点对数.n<=40000. [算法]点分治 [题解]对于一个区域,选择其重心x作为根,则划分出来的每棵子树都是子区域,可以证明至多划分log n次(通过vis[]划分区域).每次划分所有点都扫描一次,所以仅遍历的复杂度是O(n log n). 对于本题,将点x的所有子树节点dis处理出来后排序,然后用双指针法易得<=k的点对数. 但是,这样会把来自同一子树的路径也计算进去,需要减去.来自同一子树y的距离<=k的路径的数量等同于子树y内路径的距

bzoj 2631: tree 动态树+常数优化

2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1716  Solved: 576[Submit][Status] Description 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一:+ u v c:将u到v的路径上的点的权值都加上自然数c:- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树:* u v c:将u到v的

BZOJ 3282: Tree [LCT]

3282: Tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1677  Solved: 744[Submit][Status][Discuss] Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接.