Codeforces 293E

传送门:https://codeforces.com/contest/293/problem/E

题意:

给你一颗边权一开始为0的树,然后给你n-1次操作,每次给边加上边权,问你n-1次操作后有有多少对点之间的路径长度小于等于l,并且边权和小于等于w

题解:

poj1741 点分治裸题是 边权和小于等于k,这里加了一个路径条数的限制

对于这个路径条数和边权的两个限制,我们可以得到两个不等式,可以用点分治得到满足距离的一个数组a

将数组a按照距离从小到大排序后,就可以满足cdq的条件了,也是一个三维偏序问题,计数的时候需要注意一下去重

具体解释请看代码注释

代码:

#include <set>
#include <map>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
struct node {
int x, y;
int op;
bool operator < (const node &a) const {
if(x != a.x) return x < a.x;
if(y != a.y) return y < a.y;
return op < a.op;
}
node() {};
node(int _x, int _y, int _op) {
x = _x, y = _y, op = _op;
}
} a[maxn], tmp[maxn];
int cnt;
int n, L, W;
struct EDGE {
int v, w, nxt;
} edge[maxn << 1];
int head[maxn];
int tot;
void add_edge(int u, int v, int w) {
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
}
int sz[maxn], vis[maxn], mx[maxn]; int get_root(int u, int fa, int num) {
int y = 0;
mx[u] = 0;
sz[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if(!vis[v] && v != fa) {
int z = get_root(v, u, num);
// debug3(u, v, z);
sz[u] += sz[v];
mx[u] = max(mx[u], sz[v]);
if(mx[y] > mx[z]) y = z;
}
}
mx[u] = max(mx[u], num - sz[u]);
return mx[u] < mx[y] ? u : y;
}
void dfs(int u, int fa, int len, int weight) {
a[++cnt] = node(len, weight, 0);//与根节点的距离和权值 当前点 op为0
a[++cnt] = node(L - len, W - weight, 1);//还剩下可以走的距离与权值限制 限制 op为1
for(int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if(!vis[v] && v != fa) {
dfs(v, u, len + 1, weight + edge[i].w);
}
}
}
LL cdq(int l, int r) {
if(l == r) return 0;
int mid = (l + r) >> 1;
LL ans = cdq(l, mid) + cdq(mid + 1, r);
int p = l, q = mid + 1, res = 0;
for(int i = l; i <= r; i++) {//因为左边的x已经小于右边的x了,所以只要比较y就行
if((p <= mid && (a[p].y < a[q].y || (a[p].y == a[q].y && a[p].op <= a[q].op))) || q > r) {
res += a[p].op ^ 1;//如果这个点是非限制点,res++
tmp[i] = a[p++];//恢复现场
} else {
ans += a[q].op * res;//如果这个点是限制点,答案就可以增加
tmp[i] = a[q++];
}
}
for(int i = l; i <= r; i++) {
a[i] = tmp[i];
}
// debug3(l, r, ans);
return ans;
}
LL Find(int u, int len, int weight) {
LL res = 0; cnt = 0;
dfs(u, -1, len, weight);//获取a数组,即满足l,w限制的数组
// debug1(cnt);
sort(a + 1, a + cnt + 1);//对x排序
for(int i = 1; i <= cnt; i++) {
if(2 * a[i].x <= L && 2 * a[i].y <= W)
res += a[i].op ^ 1;//不满足条件的,op为0就不满足,
}
// debug1(cnt);
debug1(res);
return (cdq(1, cnt) - res) / 2;//a,b,b,a是一样的,所以除二
}
LL solve(int u, int num) {
int root = get_root(u, -1, num);//点分治 找重心 debug1(root);
cout<<"1"<<endl;
LL res = Find(root, 0, 0);//以该重心分治的贡献
cout<<"root"<<root<<"de gong xian is: ";
debug1(res);
vis[root] = 1;
for(int i = head[root]; i != -1; i = edge[i].nxt) {
int v = edge[i].v, w = edge[i].w;
if(!vis[v]) {
cout<<"2"<<endl;
res -= Find(v, 1, w);//因为这个点是由父亲节点跑过来的,所以边长为1的点重复算了需要减去
// debug1(res);//减去重复的
res += solve(v, sz[v] > sz[root] ? num - sz[root] : sz[v]);//子树大小的判断
}
}
return res;
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
mx[0] = INF;
memset(head, -1, sizeof(head));
tot = 0;
scanf("%d%d%d", &n, &L, &W);
for(int i = 2; i <= n; i++) {
int u, w; scanf("%d%d", &u, &w);
add_edge(i, u, w);
add_edge(u, i, w);
}
printf("%lld\n", solve(1, n));
return 0;
}

Codeforces 293E 点分治+cdq的更多相关文章

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

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

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

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

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

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

  4. CodeForces 293E Close Vertices 点分治

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

  5. [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解

    原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...

  6. UOJ #7 NOI2014购票(点分治+cdq分治+斜率优化+动态规划)

    重写一遍很久以前写过的题. 考虑链上的问题.容易想到设f[i]为i到1的最少购票费用,转移有f[i]=min{f[j]+(dep[i]-dep[j])*p[i]+q[i]} (dep[i]-dep[j ...

  7. codeforces 161D 点分治

    传送门:https://codeforces.com/problemset/problem/161/D 题意: 求树上点对距离恰好为k的点对个数 题解: 与poj1741相似 把点分治的模板改一下即可 ...

  8. 点分治&cdq分治 总结

    游荡的孤高灵魂不需要羁绊之处. 洛谷题单 点分治 前置芝士 树的重心 树分治 例题略解 P3806 [模板]点分治1 板子题,先暴力找到整棵树的重心,然后先求出重心到各点的距离,进而算出他所在树的各个 ...

  9. Codeforces 475D CGCDSSQ(分治)

    题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi. 表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随 ...

随机推荐

  1. 百度语音识别REST API用法(含JAVA代码)——不须要集成SDK的方法

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zpf8861/article/details/32329457 上一篇文章http://blog.c ...

  2. Directx11学习笔记【九】 3D渲染管线

    原文:Directx11学习笔记[九] 3D渲染管线 原文地址:http://blog.csdn.net/bonchoix/article/details/8298116 3D图形学研究的基本内容,即 ...

  3. 提高webpack的构建速度的几种方法概括

    通过externals配置来提取常用库 利用DllPlugin和DllReferencePlugin预编译资源模块,通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过 ...

  4. Android 高仿微信支付键盘

    现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定 ...

  5. 微信服务号获得openid 跟用户信息

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxxxx&redirect_uri=http://www. ...

  6. 巧用 PHP 数组函数

    0x00 前言 PHP 的数组是一种很强大的数据类型,与此同时 PHP 内置了一系列与数组相关的函数可以很轻易的实现日常开发的功能.但是我发现好像很多小伙伴都忽略了内置函数的作用(比如我自己就编写过一 ...

  7. 在ORACLE存储过程中创建临时表

    在ORACLE存储过程中创建临时表 存储过程里不能直接使用DDL语句,所以只能使用动态SQL语句来执行 --ON COMMIT DELETE ROWS 说明临时表是事务指定,每次提交后ORACLE将截 ...

  8. 学习微信小程序

    1.从小程序指南文档开始看起:小程序指南 2.开发者工具下载:小程序开发工具

  9. LRJ-Example-06-02-Uva514

    #define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<stack> using namespace std; + ...

  10. Project Euler Problem 16-Power digit sum

    直接python搞过.没啥好办法.看了下别人做的,多数也是大数乘法搞过. 如果用大数做的话,c++写的话,fft优化大数乘法,然后快速幂一下就好了.