2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块

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


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×avk.

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: 
  
  1N105 
  
  0ai109 
  
  0k1018
 

 

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
 
题意:给你一颗根树,求有多少点对(u,v)  u!=v满足u是v的祖先且点权au*av<=k
思路:问题转化一下,就是求对于每一个点u,以该点为根的子树下,有多少个点v的权值是小于等于(k/au + 1); 由于是子树的问题,那么可以想到的是先求出一个dfs序,将问题转化为区间查询的问题,那么问题就是,对于每个点u,在区间[st[u]+1,ed[u]]有多少个值是小于等于(k/au + 1); 求一个区间有多少个数小于莫个数G的数可以用分块实现,就是完整的块二分,两边的块暴力, 复杂度nsqrt(n)  
坑点:一直以为1就是root。。。
 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 100;
struct Edge {
    int to, nex;
}e[maxn];
int n;
ll k;
ll a[maxn];
int root;
int head[maxn], tot;
void init() {
    memset(head, -1, sizeof head);
    tot = 0;
}
void add(int u, int v) {
    e[tot].to = v;
    e[tot].nex = head[u];
    head[u] = tot++;
}
ll id[maxn];
int flag[maxn];
void input() {
    scanf("%d%I64d", &n, &k);
    memset(flag, 0, sizeof flag);
    for(int i = 0; i < n; ++i) scanf("%I64d", &a[i]);
    int u, v;
    for(int i = 1; i < n; ++i) {
        scanf("%d%d", &u, &v);
        u--; v--;
        flag[v] = 1;
        add(u, v);
    }
    for(int i = 0; i < n; ++i) if(flag[i] == 0) { root = i; break; }
}
int st[maxn], ed[maxn], tim;
void dfs(int u) {
    st[u] = ++tim;
    id[tim] = a[u];
    for(int i = head[u]; ~i; i = e[i].nex) {
        dfs(e[i].to);
    }
    ed[u] = tim;
}


const int SIZE = 937;
ll block[maxn / SIZE + 1][SIZE + 1];
void init2() {
    int b = 0, j = 0;
    for(int i = 0; i < n; ++i) {
        block[b][j] = id[i];
        if(++j == SIZE) { b++; j = 0; }
    }
    for(int i = 0; i < b; ++i) sort(block[i], block[i] + SIZE);
    if(j) sort(block[b], block[b] + j);
}

int query(int L, int R, ll v) {
    int lb = L / SIZE, rb = R / SIZE;
    int k = 0;
    if(lb == rb) {
        for(int i = L; i <= R; ++i) if(id[i] < v) k++;
    } else {
        for(int i = L; i < (lb + 1) * SIZE; ++i) if(id[i] < v) k++;
        for(int i = rb * SIZE; i <= R; ++i) if(id[i] < v) k++;
        for(int b = lb + 1; b < rb; ++b) {
            k += lower_bound(block[b], block[b] + SIZE, v) - block[b];
        }
    }
    return k;
}
void solve() {
    tim = -1;
    dfs(root);
    init2();
   ll ans = 0;
   for(int i = 0; i < n; ++i) {
        if(st[i] == ed[i]) continue;
        if(a[i] == 0) { ans += (ed[i] - st[i]); continue; }
        ll v = k / a[i] + 1;
        ans += query(st[i]+1, ed[i], v);

   }
   printf("%I64d\n", ans);
}
int main() {
#ifdef LOCAL
    freopen("in", "r", stdin);
#endif
int cas;
    while(~scanf("%d", &cas)) {
    //int cas;
        while(cas --) {
            init();
            input();
            solve();
        }
    }
    return 0;
}
View Code

 

posted @ 2016-09-11 10:27  JL_Zhou  阅读(252)  评论(0编辑  收藏  举报