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

108 篇文章 0 订阅
24 篇文章 0 订阅

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 integer T (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
  
  
1 3 3 1 2 3 1 2 2 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 1000000000000000007
struct 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 1000000000000000007
int 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
 

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

Statistic |  Submit |  Discuss | Note
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值