Codeforces 293E 点分治+cdq
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的更多相关文章
- Codeforces 1045G AI robots [CDQ分治]
洛谷 Codeforces 简单的CDQ分治题. 由于对话要求互相看见,无法简单地用树套树切掉,考虑CDQ分治. 按视野从大到小排序,这样只要右边能看见左边就可以保证互相看见. 发现\(K\)固定,那 ...
- Codeforces 848C Goodbye Souvenir [CDQ分治,二维数点]
洛谷 Codeforces 这题我写了四种做法-- 思路 不管做法怎样,思路都是一样的. 好吧,其实不一样,有细微的差别. 第一种 考虑位置\(x\)对区间\([l,r]\)有\(\pm x\)的贡献 ...
- Codeforces 526F Pudding Monsters - CDQ分治 - 桶排序
In this problem you will meet the simplified model of game Pudding Monsters. An important process in ...
- CodeForces 293E Close Vertices 点分治
题目传送门 题意:现在有一棵树,每条边的长度都为1,然后有一个权值,求存在多少个(u,v)点对,他们的路劲长度 <= l, 总权重 <= w. 题解: 1.找到树的重心. 2.求出每个点到 ...
- [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解
原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...
- 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 ...
- codeforces 161D 点分治
传送门:https://codeforces.com/problemset/problem/161/D 题意: 求树上点对距离恰好为k的点对个数 题解: 与poj1741相似 把点分治的模板改一下即可 ...
- 点分治&cdq分治 总结
游荡的孤高灵魂不需要羁绊之处. 洛谷题单 点分治 前置芝士 树的重心 树分治 例题略解 P3806 [模板]点分治1 板子题,先暴力找到整棵树的重心,然后先求出重心到各点的距离,进而算出他所在树的各个 ...
- Codeforces 475D CGCDSSQ(分治)
题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi. 表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随 ...
随机推荐
- win7 powershell版本过低问题
那台win8系统的笔记本电脑 硬盘坏掉后 在win7系统的台式机上使用 vagrant up 提示版本过低 The version of powershell currently installed ...
- 杨柳目-杨柳科-Info-新闻:“北京三害”之一,危害堪比雾霾和沙尘,杨絮为什么会肆虐
ylbtech-杨柳目-杨柳科-Info-新闻:“北京三害”之一,危害堪比雾霾和沙尘,杨絮为什么会肆虐 1.返回顶部 1. “北京三害”之一,危害堪比雾霾和沙尘,杨絮为什么会肆虐 18-05-0817 ...
- 【AtCoder Regular Contest 092】C.2D Plane 2N Points【匈牙利算法】
C.2D Plane 2N Points 题意:给定N个红点二维坐标N个蓝点二维坐标,如果红点横纵坐标都比蓝点小,那么它们能够构成一组.问最多能构成多少组. 题解:把满足要求的红蓝点连线,然后就是匈牙 ...
- Xcode 中的Bundle versions string, short 和 Bundle version 区别
Bundle version is the internal version number of your app. Short version string is the publically vi ...
- HLSL效果框架
原文:HLSL效果框架 HLSL效果框架能简化许多操作.这里先不写具体的效果框架的程序,在处理多光源光照的时候再整理. 下一章:效果框架-多种光源的多光源 叠加效果 这儿先列出效果框架的一个注意点: ...
- jQuery 链
通过 jQuery,可以把动作/方法链接在一起. Chaining 允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上). jQuery 方法链接 直到现在,我们都是一次写一条 jQue ...
- HZOJ big
考试的时候理解错题了(无语)…… 那个看似很长的式子的意义其实是逻辑左移动,就是最高位会出现在最低位的意思(这谁能看出来……).此时x取值经过那个式子后仍然可以遍历[0,2^n), O(m)枚举断点, ...
- JavaScript指定周期来调用函数setTimeout和setInterval
setTimeout方法:setTimeout setInterval方法:setInterval
- js获取dom节点
var s= document.getElementById("test");del_ff(s); //清理空格var chils= s.childNodes; //得到s的全部子 ...
- 2018-6-24-WPF-使用RPC调用其他进程
title author date CreateTime categories WPF 使用RPC调用其他进程 lindexi 2018-06-24 14:41:29 +0800 2018-2-13 ...