HDU5877 Weak Pair dfs + 线段树/树状数组 + 离散化
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5877
题意:
weak pair的要求:
1.u是v的祖先(注意不一定是父亲)
2.val[u]*val[k] <=k;
题解:
1.将val(以及k/val)离散化,可用map 或者 用数组。 只要能将val与树状数组或线段树的下标形成映射就可以了。
2.从根节点开始搜索(题目中的树,不是线段树或树状数组的树),先统计当前节点与祖先能形成多少对weak pair,然后将其插入到树状数组或线段树中。
3.递归其子树。递归完子树后,再把当前节点从树状数组或线段树中删去。因为:根据递归的特性,如果不删除,这个值将会残留在c数组, 那么他的堂兄弟,堂叔伯,堂侄子等(后一步 递归的)会误认为这个值是他的祖先的。所以要及时删除。
类似的题(边查询边更新):http://blog.csdn.net/dolfamingo/article/details/71001021
树状数组(map离散):
#include<cstdio>//hdu5877 树状数组 map离散 dfs
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#define LL long long
#define INF 2e18 using namespace std; LL sval[200020], val[200020];
int n,fa[100010],c[200010];
map<LL,int> m;
vector<int> son[100010];
LL k,ans; int lowbit(int x)
{
return x & (-x);
} void add(int x, int d)
{
for(; x<=2*n; x += lowbit(x))
{
c[x] += d;
}
} int sumc(int x)
{
int s = 0;
for(;x>0; x -= lowbit(x))
{
s += c[x];
}
return s;
} void dfs(int rt)//c数组中的下标与val[i],k/val[i]映射 且k/v[i]的下标-i的下边等于n(自己定)
{
ans += sumc(m[val[n+rt]]);//统计<=k/val[rt]的个数,为什么不直接 m[k/val[rt]]? 因为val[rt]可能为0
add(m[val[rt]],1);
for(int i = 0; i<son[rt].size(); i++)
{
dfs(son[rt][i]);
}
add(m[val[rt]],-1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k); for(int i = 1; i<=n; i++)
{
//存k/val[i]是因为 val[i]*(k/val[i])<= k. 到时可以直接从树状数组中统计<=k/val[i]的个数
scanf("%lld",&val[i]);
if(val[i])
val[n+i] = k/val[i];
else //0为特殊情况
val[n+i] = INF;
} //sval的作用是将v值按从小到大,一一与c数组的下标形成映射
for(int i = 1; i<=2*n; i++)
sval[i] = val[i];
sort(sval+1,sval+2*n+1); int cnt = 0;
m.clear();
for(int i = 1; i<=2*n; i++)
{
//map的作用是将v值与c数组的下标形成映射
if(!m[sval[i]]) m[sval[i]] = ++cnt;
} for(int i = 1; i<=n; i++)
fa[i] = 0, son[i].clear();
for(int i = 1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v] = u;
} ans = 0;
memset(c,0,sizeof(c));
for(int i = 1; i<=n; i++)
{
if(!fa[i])
{
dfs(i);
break;
}
}
printf("%lld\n",ans); }
return 0;
}
线段树(map离散):
#include<cstdio>//hdu5877 线段树 map离散 dfs
#include<cstring>//注意区分题目的树和线段树的树
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#define LL long long
#define INF 2e18 using namespace std; int n,len;//n是题目给出的树的结点个数,len是线段树的线段长度。
LL k,ans;
LL val[200100],sval[200100];//val记录原始值,sval记录经过排序,删除重复操作的值,用于线段树的操作
int fa[100100],sum[800100];
vector<int>son[100100];
map<LL,int>m; int query(int root, int le, int ri, int x, int y)
{
if(x<=le && y>=ri)
return sum[root]; int mid = (le+ri)/2, ret = 0;
if(x<=mid) ret += query(root*2,le,mid,x,y);
if(y>=mid+1) ret += query(root*2+1,mid+1,ri,x,y);
return ret;
} void update(int root, int le, int ri, int pos, int d)
{
if(le==ri)
{
sum[root] += d;
return;
} int mid = (le+ri)/2;
if(pos<=mid) update(root*2,le,mid,pos,d);
else update(root*2+1,mid+1,ri,pos,d);
sum[root] = sum[root*2] + sum[root*2+1];
} void dfs(int rt)
{
int last = m[val[n+rt]];
int pos = m[val[rt]]; ans += query(1,1,len,1,last); update(1,1,len,pos,1);
for(int i = 0; i<son[rt].size(); i++)
{
dfs(son[rt][i]);
}
update(1,1,len,pos,-1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&val[i]);
if(val[i])
val[n+i] = k/val[i];
else
val[n+i] = INF;
} for(int i = 1; i<=2*n; i++)
sval[i] = val[i];
sort(sval+1,sval+2*n+1); m.clear();
len = 0;
for(int i = 1; i<=2*n; i++)
{
if(!m[sval[i]]) m[sval[i]] = ++len;
} for(int i = 1; i<=n; i++)
fa[i] = 0, son[i].clear();
for(int i = 1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v] = u;
} ans = 0;
memset(sum,0,sizeof(sum));
for(int i = 1; i<=n; i++)
{
if(!fa[i])
{
dfs(i);
break;
}
} printf("%lld\n",ans);
}
return 0;
}
线段树(数组离散):
#include<cstdio>//hdu5877 线段树 dfs 普通数组进行离散
#include<cstring>//注意区分题目的树和线段树的树
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#define LL long long
#define INF 2e18
using namespace std; int n,m;//n是题目给出的树的结点个数,m是线段树的线段长度。
LL k,ans;
LL val[200100],sval[200100];//val记录原始值,sval记录经过排序,删除重复操作的值,用于线段树的操作
int fa[100100],sum[800100];
vector<int>son[100100]; int query(int root, int le, int ri, int x, int y)
{
if(x<=le && y>=ri)
return sum[root]; int mid = (le+ri)/2, ret = 0;
if(x<=mid) ret += query(root*2,le,mid,x,y);
if(y>=mid+1) ret += query(root*2+1,mid+1,ri,x,y);
return ret;
} void update(int root, int le, int ri, int pos, int d)
{
if(le==ri)
{
sum[root] += d;
return;
} int mid = (le+ri)/2;
if(pos<=mid) update(root*2,le,mid,pos,d);
else update(root*2+1,mid+1,ri,pos,d);
sum[root] = sum[root*2] + sum[root*2+1];
} void dfs(int rt)
{
int last = lower_bound(sval+1, sval+m+1,val[n+rt]) - sval;
int pos = lower_bound(sval+1,sval+m+1,val[rt]) - sval; ans += query(1,1,m,1,last); update(1,1,m,pos,1);
for(int i = 0; i<son[rt].size(); i++)
{
dfs(son[rt][i]);
}
update(1,1,m,pos,-1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&k);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&val[i]);
if(val[i])
val[n+i] = k/val[i];
else
val[n+i] = INF;
} for(int i = 1; i<=2*n; i++)
sval[i] = val[i];
sort(sval+1,sval+2*n+1);
m = unique(sval+1,sval+2*n+1) - (sval+1); for(int i = 1; i<=n; i++)
fa[i] = 0, son[i].clear();
for(int i = 1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
son[u].push_back(v);
fa[v] = u;
} ans = 0;
memset(sum,0,sizeof(sum));
for(int i = 1; i<=n; i++)
{
if(!fa[i])
{
dfs(i);
break;
}
} printf("%lld\n",ans);
}
return 0;
}
HDU5877 Weak Pair dfs + 线段树/树状数组 + 离散化的更多相关文章
- hdu4605 树状数组+离散化+dfs
Magic Ball Game Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- POJ 2299 【树状数组 离散化】
题目链接:POJ 2299 Ultra-QuickSort Description In this problem, you have to analyze a particular sorting ...
- BZOJ_5055_膜法师_树状数组+离散化
BZOJ_5055_膜法师_树状数组+离散化 Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...
- 2016 大连网赛---Weak Pair(dfs+树状数组)
题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 Problem Description You are given a rooted ...
- HDU - 5877 Weak Pair (dfs+树状数组)
题目链接:Weak Pair 题意: 给出一颗有根树,如果有一对u,v,如果满足u是v的父节点且vec[u]×vec[v]<=k,则称这对结点是虚弱的,问这棵树中有几对虚弱的结点. 题解: 刚开 ...
- hdu 5877 Weak Pair dfs序+树状数组+离散化
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Prob ...
- HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化
http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则 ...
- 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...
- LightOJ 1085(树状数组+离散化+DP,线段树)
All Possible Increasing Subsequences Time Limit:3000MS Memory Limit:65536KB 64bit IO Format: ...
随机推荐
- spring mvc利用MultipartResolver解析Multipart/form-data进行文件上传
之前的表单数据都是文本数据,现记录:利用MultipartResolver进行文件上传. ①首先,需引入commons-fileUpload和commons-io jar包,pom.xml文件的坐标: ...
- 网络流24T 太空飞行计划问题
题目背景 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的 ...
- Redis - 事务操作与详解
https://blog.csdn.net/J080624/article/details/81669560 写的比较清楚的一个帖子
- Swift:闭包(Closures)
一. 基本概念 闭包(Closures)是自包括的功能代码块,能够在代码中使用或者用来作为參数传值. 在Swift中的闭包与C.OC中的blocks和其他编程语言(如C#)中的lambda, java ...
- 手把手教你如何利用Meterpreter渗透Windows系统
在这篇文章中,我们将跟大家介绍如何使用Meterpreter来收集目标Windows系统中的信息,获取用户凭证,创建我们自己的账号,启用远程桌面,进行屏幕截图,以及获取用户键盘记录等等. 相关Payl ...
- java实验8-Java输入输出流
1 读写文件 [实验目的] (1)掌握文本文件的读写方法. (2)掌握随机文件的读写方法. (3)掌握InputStream.OutputStream抽象类的基本使用. (4)掌握FileInputS ...
- 程序猿的量化交易之路(30)--Cointrader之ConfigUtil(17)
转载须注明出处:viewmode=contents">http://blog.csdn.net/minimicall?viewmode=contents.http://cloudtra ...
- Solaris 目录与文件管理
熟悉系统目录结构 掌握27个常用命令 掌握针对目录.文件的操作 掌握查找与文件内容的操作 一.命令 命令:内部命令(不依赖其他文件,可以直接执行)与外部命令 .他是用于实现某一类功能的指令或程序,其执 ...
- 简单的看Unicode和UTF-8的区别
作者:uuspider链接:http://www.zhihu.com/question/23374078/answer/65352538来源:知乎著作权归作者所有,转载请联系作者获得授权. 举一个例子 ...
- 每天一个linux命令(23):Linux 目录结构(转)
对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只管重要,下面 ...