hdu5877 dfs序+树状数组

题意:

有根树,n个点,点的权重w[i] , K 

求这样的<u , v> 总对数,满足:

     u是v的祖先,且w[u]*w[v] <= K  


做法:dfs序 + 树状数组(求区间<=q的个数)


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) {
		new HDU5877().solve();
	}
}

class HDU5877 {
	class Wall implements Comparable<Wall> {
		long high;
		int id;

		public Wall(long high, int id) {
			this.high = high;
			this.id = id;
		}

		public int compareTo(Wall o) {
			return Long.compare(high, o.high);
		}
	}

	class Ask implements Comparable<Ask>{
		int left;
		int right;
		long high ;

		Ask(int left, int right, long high) {
			this.high = high ;
			this.left = left;
			this.right = right;
		}

		@Override
		public int compareTo(Ask o) {
			return Long.compare(o.high , high) ;
		}
	}

	InputReader in = new InputReader(System.in);
	PrintWriter out = new PrintWriter(System.out);
	final int N = 100008;
	int n;
	Wall[] walls = new Wall[N];
	Ask[] asks = new Ask[N];
	int[] c = new int[N];

	int lowbit(int x) {
		return x & (-x);
	}

	void add(int i) {
		for (; i <= n; i += lowbit(i))
			c[i] += 1;
	}

	int sum(int i) {
		int s = 0;
		for (; i > 0; i -= lowbit(i))
			s += c[i];
		return s;
	}

	int sum(int l, int r) {
		return sum(r) - sum(l - 1);
	}
	
	long[] w = new long[N] ;
	int[] inDe = new int[N] ;
	int[] leftId = new int[N] ;
	int[] rightId = new int[N] ;
	int dfsTime ;
	void dfs(int u , int father){
		leftId[u] = ++dfsTime ;
		for(int i = head[u] ; i != -1 ; i = e[i].next){
			int v = e[i].v ;
			if(v == father) continue ;
			dfs(v , u) ;
		}
		rightId[u] = dfsTime ; 
	}
	
	void solve() {
		
		int t = in.nextInt() ;
		while(t-- > 0){
			n = in.nextInt() ;
			long K = in.nextLong() ;
			for(int i = 1 ; i <= n ; i++) w[i] = in.nextLong() ;
			eid = 0 ;
			Arrays.fill(head , 0 , 1+n , -1) ;
			Arrays.fill(inDe , 0 , 1+n , 0) ;
			for(int i = 1 ; i < n ; i++){
				int u = in.nextInt() ;
				int v = in.nextInt() ;
				addEdge(u , v) ;
				inDe[v]++ ;
			}
			
			int root = -1 ;
			for(int i = 1 ; i <= n ; i++){
				if(inDe[i] == 0 ){
					root = i ; 
					break ; 
				}
			}
			
			dfsTime = 0 ; 
			dfs(root, -1) ;
			
			for (int i = 1; i <= n; i++)
				walls[i] = new Wall(w[i] , leftId[i]) ;
			for (int i = 1; i <= n ; i++)
				asks[i] = new Ask(leftId[i]  , rightId[i] , w[i]) ;

			Arrays.sort(walls, 1, 1 + n) ;
			Arrays.sort(asks, 1, 1 + n) ;
			Arrays.fill(c, 0) ;

			long res = 0 ; 
			int pos = 1 ;
			for (int i = 1; i <= n; i++) {
				if(asks[i].high == 0){
					res += asks[i].right - asks[i].left ;
					continue ;
				}
				long limit = K / asks[i].high ;
				while (pos <= n && walls[pos].high <= limit) {
					add(walls[pos].id) ;
					pos++;
				}

				res += sum(asks[i].left+1 , asks[i].right) ;
			}

			out.println(res) ;
		}
		
		out.flush() ;
	}
	
	
	class Edge{
		int v ; 
		int next ;
	    Edge(int v , int next){
	    	this.v = v ; 
	    	this.next = next ;
		}
	}
	Edge[] e = new Edge[N] ;
	int[] head = new int[N] ;
	int eid ;
	void addEdge(int u , int v){
		e[eid] = new Edge(v, head[u]) ;
		head[u] = eid++ ;
	}

}

class InputReader {
	public BufferedReader reader;
	public StringTokenizer tokenizer;

	public InputReader(InputStream stream) {
		reader = new BufferedReader(new InputStreamReader(stream), 32768);
		tokenizer = new StringTokenizer("");
	}

	private void eat(String s) {
		tokenizer = new StringTokenizer(s);
	}

	public String nextLine() {
		try {
			return reader.readLine();
		} catch (Exception e) {
			return null;
		}
	}

	public boolean hasNext() {
		while (!tokenizer.hasMoreTokens()) {
			String s = nextLine();
			if (s == null)
				return false;
			eat(s);
		}
		return true;
	}

	public String next() {
		hasNext();
		return tokenizer.nextToken();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}

	public BigInteger nextBigInteger() {
		return new BigInteger(next());
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值