HDU5877:Weak Pair(树状数组+离散化+DFS序)

Weak Pair

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 5448    Accepted Submission(s): 1564

Problem Description

You are given a rooted tree of N nodes, labeled from 1 to N. To the ith 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?

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

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

2016 ACM/ICPC Asia Regional Dalian Online

题解:离散化,DFS序,利用树状数组维护前缀和。

对于x,要求y使得x*y<=k的个数,即求y<=k/x的个数,所以只需求用树状数组求小于等于k/x的个数。前提是要离散化

DFS序经过x时求一遍,回到x时再求一遍,两个前缀和一减,便求得y的个数

#include <bits/stdc++.h>
using namespace std;
int const N = 100000 + 10;
typedef long long ll;
ll const inf = 0x3f3f3f3f3f3f3f3f;
ll k,ans,a[N];
int n,t,tot,in[N],c[N],root;
int first[N],ne[2*N],to[2*N];
vector<ll>v;
int lowbit(int i){
	return i&-i;
}
void add(int x,int d){
	while(x <= v.size()){
		c[x] += d;
		x += lowbit(x);
	}
}
ll query(int x){
	ll ret = 0;
	while(x){
		ret += (ll)c[x];
		x -= lowbit(x);
	}
	return ret;
}
void insert(int x,int y){
	ne[++tot] = first[x];
	to[tot] = y;
	first[x] = tot;
}
void dfs(int x,int fa){
	add(lower_bound(v.begin(),v.end(),a[x])-v.begin()+1,1);
	int tmp = lower_bound(v.begin(),v.end(),a[x]?k/a[x]:inf)-v.begin()+1;
	ll pre = query(tmp);
	for(int i=first[x];i;i=ne[i]){
		int v = to[i];
		if(v == fa)	continue;
		dfs(v,x);
	}
	ans += query(tmp) - pre;
}
void Init(){
	v.clear();
	memset(c,0,sizeof(c));
	memset(in,0,sizeof(in));
	memset(first,0,sizeof(first));
	ans = tot = 0;
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		v.push_back(a[i]);
		if(!a[i])	v.push_back(inf);    //a[i]可以为0!!!
		else v.push_back(k/a[i]);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	for(int i=1;i<=n-1;i++){   //x是y的父亲,有序
		int x,y;
		scanf("%d%d",&x,&y);
		insert(x,y);
		in[y]++;
	}
	for(int i=1;i<=n;i++)   //找到根节点
		if(!in[i]){
			root = i;	
			break; 
		} 
}
int main(){
	scanf("%d",&t);
	while(t--){
		Init();
		tot = 0;
		dfs(root,-1);
		printf("%lld\n",ans);
	}
}

 

posted @ 2019-02-07 15:57  月光下の魔术师  阅读(4)  评论(0)    收藏  举报