描述:
Weak Pair
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2106 Accepted Submission(s): 647
Problem Description
You are given a
rooted
tree of
N
nodes, labeled from 1 to
N
. To the
i
th node a non-negative value
ai
is assigned.An
ordered
pair of nodes
(u,v)
is said to be
weak
if
(1) u is an ancestor of v (Note: In this problem a node u is not considered an ancestor of itself);
(2) au×av≤k .
Can you find the number of weak pairs in the tree?
(1) u is an ancestor of v (Note: In this problem a node u is not considered an ancestor of itself);
(2) au×av≤k .
Can you find the number of weak pairs in the tree?
Input
There are multiple cases in the data set.
The first line of input contains an integer T denoting number of test cases.
For each case, the first line contains two space-separated integers, N and k , respectively.
The second line contains N space-separated integers, denoting a1 to aN .
Each of the subsequent lines contains two space-separated integers defining an edge connecting nodes u and v , where node u is the parent of node v .
Constrains:
1≤N≤105
0≤ai≤109
0≤k≤1018
The first line of input contains an integer T denoting number of test cases.
For each case, the first line contains two space-separated integers, N and k , respectively.
The second line contains N space-separated integers, denoting a1 to aN .
Each of the subsequent lines contains two space-separated integers defining an edge connecting nodes u and v , where node u is the parent of node v .
Constrains:
1≤N≤105
0≤ai≤109
0≤k≤1018
Output
For each test case, print a single integer on a single line denoting the number of weak pairs in the tree.
Sample Input
1 2 3 1 2 1 2
Sample Output
1
Source
Recommend
有一棵树,N个结点,N-1条边,每个结点有权值ai,如果存在一个点对,由结点和它的祖先组成,
并且它们相乘的结果<=K,那么这个点对就称为weak,求有多少个这样的点对。
思路:
要求w[u]*w[v]<=k,那么到v的时候,所有小于等于k/w[v]的u都满足,可以想到树状数组(光是DFS会T)。结点的值最大10亿,肯定要离散化,离散化的时候要把k/w[v]加进去一起离散,还要注意权值ai可以为0,这个只要把大于1e5的任一个数加进去a[]就好了。第一个要求u 是v 的祖先,那么可以dfs,遍历到v时,要使上方的都是满足第一条件的u,即遍历完某个节点u的子树时,这时u不可能是任何节点的祖先 删除u,这样就能保证所有有贡献的都是祖先。复杂度O(nlogn)
PS:大连区域赛网赛最后一题,做的时候只用了DFS,一直T,之前做过树状数组的题,不过做的少,意识还不够强_(:зゝ∠)_
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#define ll __int64
using namespace std;
const int N=1e5+10;
int vis[N];
int in[N];//in[i]为0的为root
int bit[N<<1],n;
vector<int>e[N];
ll k,ans;
ll a[N<<1],li[N<<1];
int sum(int i){
int s=0;
while(i>0){
s+=bit[i];
i-=i&-i;
}
return s;
}
void add(int i,int x){
while(i<=2*n){
bit[i]+=x;
i+=i&-i;
}
}
void dfs(int rt){
vis[rt]=1;
ans+=sum(a[rt+n]);//在它之前进入的都为它的祖先
add(a[rt], 1);
for(int i=0; i<e[rt].size(); i++){
int son=e[rt][i];
if(!vis[son]){
dfs(son);
}
}
add(a[rt], -1);//该节点的子树全都遍历完了 该节点不是任何节点的祖先时 删除该节点的值
}
void lisan(ll x[]){//离散化模板
for(int i=1; i<=2*n; i++)li[i]=x[i];
sort(li+1, li+2*n+1);//unique的作用是“去掉”容器中相邻元素的重复元素,它实质上是一个伪去除,
int m=unique(li+1, li+2*n+1)-li-1;//它会把重复的元素添加到容器末尾,而返回值是去重之后的尾地址
for(int i=1; i<=2*n; i++)x[i]=lower_bound(li+1, li+m+1, x[i])-li;//一般使用前需要对容器进行排序
}//m也等于去重数组的大小
int main(){
// #ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
// #endif
int t;
scanf("%d",&t);
while(t--){
memset(bit, 0, sizeof(bit));
memset(vis, 0, sizeof(vis));
memset(in, 0, sizeof(in));
ans=0;
scanf("%d%I64d",&n,&k);
for(int i=1; i<=n; i++){
e[i].clear();
}
for(int i=1; i<=n; i++){
scanf("%I64d",&a[i]);
if(a[i]==0)a[i+n]=N;
else a[i+n]=k/a[i];
}
lisan(a);//数据a[i]<=10^9 n<=10^5 数据离散化使a[i]的范围中10^5内
//使得树状数组的空间不溢出
for(int i=1; i<=n-1; i++){
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
in[v]++;
}
int rt;
for(int i=1; i<=n; i++){
if(!in[i]){
rt=i;break;
}
}
dfs(rt);
printf("%I64d\n",ans);
}
return 0;
}

本文介绍了一种解决弱对问题的方法,通过树状数组和离散化的应用,在一棵带权值的树中寻找符合条件的弱对。利用DFS遍历树,并结合树状数组优化查找过程,实现了高效求解。

456

被折叠的 条评论
为什么被折叠?



