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. codevs1839 洞穴勘测

    题目描述 Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道 ...

  2. jq方法的注意点

    当jq方法里面引用的ajax方法和其它方法时,就需要把ajax改为同步,通过ajax方法返回值来判断下一步执行那个方法,你不做判断,浏览器编译执行的时候不会不会按你想的从上之下执行下来. 当安卓手机跟 ...

  3. Hdu 2522 hash

    题目链接 题意:输入整数n (1<= abs(n) <= 10^5) , 输出 1/n. 这题不是自己做出来的...看了网上的思路.这种题目都能想到用hash..反正我是没往那里想,看到循 ...

  4. font-weight:bolder与设置数值的区别

    我之前设置了font-weight:bolder;一直不明白为什么在浏览器上显示最后的效果就变成了normal呢,后来查了一下才发现bolder是相对父元素的. 如果父对象的值为 normal,子对象 ...

  5. 20.libgdx,stage中默认相机的使用

    主要思路: 通过查资料得知,stage中的默认封装的相机为OrthographicCamera,要操纵该相机,直接把他转化为OrthographicCamera即可使用 但是这会导致一个问题,即原本固 ...

  6. HUD-1708_FatMouse and Cheese

    FatMouse and Cheese Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...

  7. Gym - 101480D_Digit Division

    题意:输入n,m,将n分段,每一段都可以被m整除,有多少种方法. 题解:找到n最多可以分成多少段,1段1中分法,2段2中分法,3段4种分法--计算可知若有x段则2^x-1种分法. 注意:如果n无法被m ...

  8. @topcoder - TCO19 Regional Wildcard Wildcard Round - D1L2@ Diophantine

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 令 p[] 为质数序列:p[0] = 2, p[1] = 3, ...

  9. LeetCode81 Search in Rotated Sorted Array II

    题目: Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed? Would t ...

  10. Python 基础02 基本数据类型

    简单的数据类型以及赋值 变量不需要声明 Python的变量不需要声明,你可以直接输入: >>> a = 10 那么你的内存里就有了一个变量a,它的值是10,它的类型是 integer ...