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. MUI - 打开页面默认弹出键盘及返回关闭键盘

    打开页面默认弹出键盘及返回关闭键盘 http://www.cnblogs.com/phillyx/ (function(keyboard) { var openSoftKeyboard = funct ...

  2. KiCad 5.1.0 镜像圆弧后错位问题

    KiCad 5.1.0 镜像圆弧后错位问题 看官方回复这个问题将在 5.1.3 进行修复,因为这段时间在举行 KiCon 活动. 看到这个问题并不是非常严重,不是致命的,所以已经从 5.1.0 跳到 ...

  3. jQuery 图片高亮显示

    主要的jQuery代码: $(function() { $("ul li").hover(function() { // over //鼠标移入当前列透明度为1 其他列为0.5 $ ...

  4. Java面向对象----方法重载

    方法重载(over load):方法名相同,参数列表不同,返回类型无关 package com.tanlei.newer; public class OverLoadDemo { public sta ...

  5. 瑞星推国内唯一Linux系统杀毒软件 国产操作系统还需国产安全软件保护

    近来在IT领域最爆炸的新闻莫过于5月20日中央国家机关政府採购中心下发通知.要求中央机关採购所有计算机类产品不同意安装Windows 8.而改用国产Linux操作系统. 此消息一出,立马引起各界关注. ...

  6. JPA使用nativequery多表关联查询返回自定义实体类

    本文为JPA的学习采坑,如有问题欢迎指正. JPA官方推荐的多表关联查询使用不便,接触的有些项目可能会使用JPA 做简单查询,Mybaits做复杂查询.所以想要寻找一种好用的解决方案. JPA多表关联 ...

  7. MySQL统计同比环比SQL

    大体思路: MySQL没有类似oracle方便的统计函数,只能靠自己去硬计算:通过时间字段直接增加年份.月份,然后通过left join关联时间字段去计算环比.同比公式即可 原始表结构: 求同比SQL ...

  8. part12.5-定时器去抖

  9. 【vb.net机房收费系统】之没有包含要从继承的组件的已生成程序集 标签: vb.net继承 2015-05-02 15:19 1012人阅读

    在敲到组合查询这个功能的时候,需要用到窗体的继承,但是在新建继承窗体的时候,出现了错误(没有包含要从继承的组件的已生成程序集).如下图: 问题的产生:当时没怎么注意,也不知道怎么弄的,最后反正是继承上 ...

  10. 快递查询API接口集成,有需要的可以直接用

    适用于涉及经常发货.寄快递的人群.企业.电商网站.微信公众号平台等对接使用.支持国内外三百多家快递及物流公司的快递单号一站式查询. 使用说明: 1.KuadidiAPI.php 不需要修改改任何东西 ...