hdu 5314 Happy King 树点分冶 树状数组

来源:互联网 发布:工作备忘录软件 编辑:程序博客网 时间:2024/06/04 17:49

Happy King

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 434    Accepted Submission(s): 79


Problem Description
There are n cities and n1 roads in Byteland, and they form a tree. The cities are numbered 1 through n. The population in i-th city is pi.

Soda, the king of Byteland, wants to travel from a city u to another city v along the shortest path. Soda would be happy if the difference between the maximum and minimum population among the cities passed is **no larger than**D. So, your task is to tell Soda how many different pairs (u,v) that can make him happy.
 

Input
There are multiple test cases. The first line of input contains an integerT(1T500), indicating the number of test cases. For each test case:

The first line contains two integers n and D(1n100000,1D109).

The second line contains n integers p1,p2,,pn(0pi109).

Each of the following n1 lines describing roads contains two integers u,v(1u,vn,uv) meaning that there is a road connecting city u and city v.

It is guaranteed that the total number of vertices in the input doesn't exceed 5×105.
 

Output
For each test case, output the number of different pairs that can make Soda happy.
 

Sample Input
13 31 2 31 22 3
 

Sample Output
6
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
题意,给出一个树,要求,其中,结点u - v的路径上最大值与最小值相差不超过k的个数。
与上一题是相同的做法。树点分冶

设分治中心为ggg, 我们只需要计算跨过ggg的答案, 其他的可以分治计算.

跨过根的可以容斥做, 没有限制的 - ∑端点落在同一颗子树上的. 上述两个过程是一样的, 于是只考虑没有限制的怎么做.

xi,yix_i,y_ixi,yiiiiggg路径上的最大值和最小值. 我们按照xix_ixi排序, 然后枚举xix_ixi必选, 那么前面可选的xj,yj(j<i)x_j, y_j (j < i)xj,yj(j<i)必须要满足xi−d≤xj,xi−d≤yjx_i - d \le x_j, x_i - d \le y_jxidxj,xidyj, 由于xj≥yjx_j \ge y_jxjyj, 只需要考虑xi−d≤yjx_i - d \le y_jxidyj. 于是只要枚举xix_ixi然后用树状数组统计答案即可. 复杂度是O(nlog2n)O(n \log^2 n)O(nlog2n).

#define N 100050#define M 100005#define maxn 205#define MOD 1000000000000000007struct TreeNum{    int a[N],n;    //树状数组模板    void init(int nn){        n = nn + 1;        for(int i = 0;i<=n + 1;i++) a[i] = 0;    }    int lowbit(int x)    {        return x & (-x);    }    void modify(int x,int add)//一维    {        while(x<=n)        {            a[x]+=add;            x+=lowbit(x);        }    }    int get_sum(int x)    {        if(x < 0) return 0;        if(x > n) x = n;        int ret=0;        while(x!=0)        {            ret+=a[x];            x-=lowbit(x);        }        return ret;    }};int T,n,m,k,u,v,l,center,all,num,nodes[N],dp[N],xx[N],yy[N],pri[N],mymap[N],no;__int64 ans;bool vis[N];vector<pii> p[N];vector<pii> depV;TreeNum mytree;void findRoot(int root,int fa){    nodes[root] = 1;dp[root] = 0;    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            findRoot(g,root);            nodes[root] += nodes[g];            dp[root] = max(dp[root],nodes[g]);        }    }    dp[root] = max(dp[root],all - nodes[root]);    if(dp[root] < num){        num = dp[root];center = root;    }}int getRoot(int root,int sn){    num = INF;all = sn;center = root;    findRoot(root,-1);    return center;}void getDp(int root,int fa){    nodes[root] = 1;    depV.push_back(mp(xx[root],root));    mymap[no++] = yy[root];    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            xx[g] = max(xx[root],pri[g]);            yy[g] = min(yy[root],pri[g]);            getDp(g,root);            nodes[root] += nodes[g];        }    }}int getIndex(int x){    return lower_bound(mymap,mymap + no,x) - mymap;}__int64 cal(int root,bool isfirst){    depV.clear();no = 0;    if(isfirst)        xx[root] = pri[root],yy[root] = pri[root];    getDp(root,-1);    sort(depV.begin(),depV.end());    sort(mymap,mymap + no);    no = unique(mymap,mymap + no) - mymap;    __int64 sum = 0;    mytree.init(no);    for(int i = 0;i < depV.size();i++){        int xi = depV[i].first,yi = yy[depV[i].second];        if(xi - yi <= k ){            int goal = getIndex(xi - k);            sum += (__int64)(mytree.get_sum(no + 1) - mytree.get_sum(goal));        }        mytree.modify(getIndex(yi) + 1,1);    }    return sum;}void work(int root,int fa){    vis[root] = true;    ans += cal(root,true);    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            ans -= cal(g,false);            work(getRoot(g,nodes[g]),-1);        }    }}int main(){    while(S(T)!=EOF)    {        while(T--){            S2(n,k);            ans = 0;            FI(n) p[i + 1].clear(),vis[i + 1] = false;            FI(n) scan_d(pri[i+1]);            FI(n-1){                S2(u,v);                p[u].push_back(mp(v,1));                p[v].push_back(mp(u,1));            }            work(getRoot(1,n),-1);            printf("%I64d\n",ans * 2);        }    }    return 0;}

方法二,由于第一种方法是排序的x,那么y就是无序的,所以要用离散化加树状数组的方法来解决,但,如果换一个思路,排序y,在yi有序的情况下,不需要使用树状数组,只要用个二分找答案就可以了。为什么这样是对的呢,此时,yj < yi 由于,加入数组的都是满足xi - yi <=k的,所以只需要,yj < xi - k,那么,就一定是解了。

这种方法虽然也是n * logn * logn的复杂度,但由于没有使用高级数据结构所以,常数要小很多。

#define N 100050#define M 100005#define maxn 205#define MOD 1000000000000000007int T,n,m,k,u,v,l,center,all,num,nodes[N],dp[N],xx[N],yy[N],pri[N],no;__int64 ans;bool vis[N];vector<pii> p[N];pii mymap[N];void findRoot(int root,int fa){    nodes[root] = 1;dp[root] = 0;    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            findRoot(g,root);            nodes[root] += nodes[g];            dp[root] = max(dp[root],nodes[g]);        }    }    dp[root] = max(dp[root],all - nodes[root]);    if(dp[root] < num){        num = dp[root];center = root;    }}int getRoot(int root,int sn){    num = INF;all = sn;center = root;    findRoot(root,-1);    return center;}void getDp(int root,int fa){    nodes[root] = 1;    xx[root] = max(xx[fa],pri[root]);    yy[root] = min(yy[fa],pri[root]);    if(xx[root] - yy[root] <= k)        mymap[no++] = mp(yy[root],xx[root]);    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            getDp(g,root);            nodes[root] += nodes[g];        }    }}__int64 cal(int root,bool isfirst){    no = 0;    if(isfirst)        xx[root] = pri[root],yy[root] = pri[root];    getDp(root,root);    sort(mymap,mymap + no);    __int64 sum = 0;    for(int i = 0;i < no;i++){        sum += (__int64)(i - (lower_bound(mymap,mymap + i,mp(mymap[i].second - k,0)) - mymap));    }    return sum;}void work(int root,int fa){    vis[root] = true;    ans += cal(root,true);    FI(p[root].size()){        int g = p[root][i].first;        if(g != fa && !vis[g]){            ans -= cal(g,false);            work(getRoot(g,nodes[g]),-1);        }    }}int main(){    while(S(T)!=EOF)    {        while(T--){            S2(n,k);            ans = 0;            FI(n) p[i + 1].clear(),vis[i + 1] = false;            FI(n) scan_d(pri[i+1]);            FI(n-1){                S2(u,v);                p[u].push_back(mp(v,1));                p[v].push_back(mp(u,1));            }            work(getRoot(1,n),-1);            printf("%I64d\n",ans * 2);        }    }    return 0;}


Source
BestCoder 1st Anniversary ($)
 

Recommend
hujie   |   We have carefully selected several similar problems for you:  5338 5337 5336 5335 5334 
 

Statistic | Submit | Discuss | Note
0 0