题目传送门

题意:现在有一棵树,每条边的长度都为1,然后有一个权值,求存在多少个(u,v)点对,他们的路劲长度 <= l, 总权重 <= w.

题解:

1.找到树的重心。

2.求出每个点到中心的长度和权值。

3.对所有点都询问出合法点的个数(包括同一颗子树)加到答案上。

4.对于每一棵子树内部都找到合法点的个数从答案中减去。

5.递归处理每一颗子树。

我们现在最大的问题就是怎么计算合法点的个数。

我们把点的信息记录下来之后,按照权重从小到达排序。

然后我们就可以用2个端点维护出 a[l].weight + a[r].weight <= d

这样对于l来说, [l+1,r]里面的所有点都满足权重的条件了。

然后就只需要询问 [l+1,r]里面的点的深度 <= l - deep[i]的个数了,对于这个个数我们用树状数组去维护这个信息,一开始我们把所有的点的深度都加到树状数组里面,然后每次端点移动位置的时候都把当前点的深度从树状数组中移除,这样我们维护出了一颗[ l+1 , r] 里面的点的深度信息了。

代码:

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 5e5 + ;
int n, len, w;
int tree[N];
int root, sz[N], mxr;
int vis[N];
int head[N], to[N*], nt[N*], ct[N*];
void add(int x, int v){
for(int i = x; i <= n && i; i += i & (-i))
tree[i] += v;
}
int query(int x){
int ret = ;
for(int i = x; i; i -= i&(-i))
ret += tree[i];
return ret;
}
void getW(int o, int u, int num){
sz[u] = ;
int mx = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(vis[v] || v == o) continue;
getW(u, v, num);
sz[u] += sz[v];
mx = max(mx, sz[v]);
}
if(o) mx = max(mx, num-sz[u]);
if(mx < mxr) mxr = mx, root = u;
}
//pll p[N];
struct Node {
int fi, se;
bool operator < (const Node & x) const {
if(fi == x.fi) return se < x.se;
return fi < x.fi;
}
}p[N];
LL cal(int l, int r){
if(l >= r) return ;
sort(p+l, p+r+);
LL ans = ;
for(int i = l; i <= r; i++) add(p[i].se, );
for(int L = l, R = r; L <= R; L++){
while(L < R && p[L].fi + p[R].fi > w) {
add(p[R].se, -);
R--;
}
add(p[L].se, -);
if(L >= R) break;
ans += query(max(, len-p[L].se));
}
return ans;
} int sum = ;
void Dfs(int o, int u, int deep, int w){
sz[u] = ;
++sum;
p[sum].fi = w;
p[sum].se = deep;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || vis[v]) continue;
Dfs(u, v, deep+, w+ct[i]);
sz[u] += sz[v];
}
}
LL ans = ;
void GG(int id, int num){
if(num == ){
return ;
}
mxr = inf;
getW(, id, num);
vis[root] = ;
int ls = ; sum = ;
for(int i = head[root]; ~i; i = nt[i]){
int v = to[i];
if(vis[v]) continue;
Dfs(, to[i], , ct[i]);
ans -= cal(ls, sum);
ls = sum + ;
}
sum++;
p[sum].fi = p[sum].se = ;
ans += cal(, sum);
//cout << query(n) << endl;
for(int i = head[root]; ~i; i = nt[i]){
int v = to[i];
if(vis[v]) continue;
GG(v, sz[v]);
}
}
int tot = ;
void add(int u, int v, int w){
to[tot] = v;
ct[tot] = w;
nt[tot] = head[u];
head[u] = tot++;
}
int main(){
memset(head, -, sizeof(head));
scanf("%d%d%d", &n, &len, &w);
int u, v, val;
for(int i = ; i <= n; i++){
u = i;
scanf("%d%d", &v, &val);
add(u, v, val);
add(v, u, val);
}
GG(, n);
printf("%I64d\n", ans);
return ;
}

CodeForces 293E Close Vertices 点分治的更多相关文章

  1. codeforces 293E Close Vertices

    题目链接 正解:点分治+树状数组. 点分治板子题,直接点分以后按照$w$排序,扫指针的时候把$w$合法的路径以$l$为下标加入树状数组统计就行了. 写这道题只是想看看我要写多久..事实证明我确实是老年 ...

  2. CF 293E Close Vertices——点分治

    题目:http://codeforces.com/contest/293/problem/E 仍旧是点分治.用容斥,w的限制用排序+两个指针解决, l 的限制就用树状数组.有0的话就都+1,相对大小不 ...

  3. Codeforces 293E 点分治+cdq

    Codeforces 293E 传送门:https://codeforces.com/contest/293/problem/E 题意: 给你一颗边权一开始为0的树,然后给你n-1次操作,每次给边加上 ...

  4. ●CodeForce 293E Close Vertices

    题链: http://codeforces.com/contest/293/problem/E题解: 点分治,树状数组 大致思路和 POJ 1741 那道点分治入门题相同, 只是因为多了一个路径的边数 ...

  5. Codeforces 833D Red-Black Cobweb [点分治]

    洛谷 Codeforces 思路 看到树上路径的统计,容易想到点分治. 虽然只有一个限制,但这个限制比较麻烦,我们把它拆成两个. 设黑边有\(a\)条,白边有\(b\)条,那么有 \[ 2a\geq ...

  6. Codeforces 1045G AI robots [CDQ分治]

    洛谷 Codeforces 简单的CDQ分治题. 由于对话要求互相看见,无法简单地用树套树切掉,考虑CDQ分治. 按视野从大到小排序,这样只要右边能看见左边就可以保证互相看见. 发现\(K\)固定,那 ...

  7. Codeforces 848C Goodbye Souvenir [CDQ分治,二维数点]

    洛谷 Codeforces 这题我写了四种做法-- 思路 不管做法怎样,思路都是一样的. 好吧,其实不一样,有细微的差别. 第一种 考虑位置\(x\)对区间\([l,r]\)有\(\pm x\)的贡献 ...

  8. Codeforces 938G Shortest Path Queries [分治,线性基,并查集]

    洛谷 Codeforces 分治的题目,或者说分治的思想,是非常灵活多变的. 所以对我这种智商低的选手特别不友好 脑子不好使怎么办?多做题吧-- 前置知识 线性基是你必须会的,不然这题不可做. 推荐再 ...

  9. Codeforces 526F Pudding Monsters - CDQ分治 - 桶排序

    In this problem you will meet the simplified model of game Pudding Monsters. An important process in ...

随机推荐

  1. jdk1.8源码解析:HashMap底层数据结构之链表转红黑树的具体时机

    本文从三个部分去探究HashMap的链表转红黑树的具体时机: 一.从HashMap中有关“链表转红黑树”阈值的声明: 二.[重点]解析HashMap.put(K key, V value)的源码: 三 ...

  2. Confluence未授权模板注入/代码执行(CVE-2019-3396)

    --- title: Confluence未授权模板注入/代码执行(CVE-2019-3396) tags: [poc,cve] num :g7y12 --- # 简介 --- Confluence是 ...

  3. JAVA常用的集合类

    package com.xian.test; import java.util.ArrayList; import java.util.Enumeration; import java.util.Ha ...

  4. maysql的自增字段

    因为mysql中的自增字段与oracle数据库是不一样的,所以在这里唠嗑一下mysql的自增字段 1.添加自增字段 1.1 在创建表时添加 create table emp( empno ) auto ...

  5. 4、一个打了鸡血的for循环(增强型for循环)

    对于循环,我们大家应该都不陌生,例如do-while循环,while循环,for循环,今天给大家介绍一个有趣的东西——打了鸡血的for循环(增强型for循环). 首先看代码,了解一下for循环的结构: ...

  6. zookeeper基本知识入门(一)

    之前我们在搭建hadoop分布式环境的时候用到过Zookeeper注册hadoop服务.那么到底Zookeeper在分布式环境中发挥了什么作用呢,这次我们就来讨论这个问题. 在分布式系统中通常都会有多 ...

  7. java多线程中wait/notify/sleep/join/yield方法以及多线程的六种状态

    刚开始学线程的时候也是被这几个方法搞的云里雾里的,尤其是一开始看的毕老师的视频,老师一直在强调执行权和执行资格,看的有点懵逼,当然不是说毕老师讲的不好,就是自己有点没听明白,后来复习看了一些其他的博客 ...

  8. 多线程 共享资源 同步锁 java

    Java多线程编程:Lock   synchronized是java中的一个关键字,也就是说是Java语言内置的特性.那么为什么会出现Lock呢? 如果一个代码块被synchronized修饰了,当一 ...

  9. Java学习|强引用,软引用,弱引用,幻想引用有什么区别?

    在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用:Java中根据其生命周期的长短,将引用分为4类. 1 强引用 特点:我们平常典型编码Object obj = new Objec ...

  10. 如何删除GIT仓库中的敏感信息

    如何删除GIT仓库中的敏感信息 正常Git仓库中应该尽量不包含数据库连接/AWS帐号/巨大二进制文件,否则一旦泄漏到Github,这些非常敏感信息会影响客户的信息安全已经公司的信誉.公司可能其它还有相 ...