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
n−1
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.
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
(1≤T≤500)
, indicating the number of test cases. For each test case:
The first line contains two integers n and D (1≤n≤100000,1≤D≤109) .
The second line contains n integers p1,p2,…,pn (0≤pi≤109) .
Each of the following n−1 lines describing roads contains two integers u,v (1≤u,v≤n,u≠v) 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 .
The first line contains two integers n and D (1≤n≤100000,1≤D≤109) .
The second line contains n integers p1,p2,…,pn (0≤pi≤109) .
Each of the following n−1 lines describing roads contains two integers u,v (1≤u,v≤n,u≠v) 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
6HintIf you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
题意,给出一个树,要求,其中,结点u - v的路径上最大值与最小值相差不超过k的个数。
与上一题是相同的做法。
树点分冶
设分治中心为g, 我们只需要计算跨过g的答案, 其他的可以分治计算.
跨过根的可以容斥做, 没有限制的 - ∑端点落在同一颗子树上的. 上述两个过程是一样的, 于是只考虑没有限制的怎么做.
令xi,yi为i到g路径上的最大值和最小值. 我们按照xi排序, 然后枚举xi必选, 那么前面可选的xj,yj(j<i)必须要满足xi−d≤xj,xi−d≤yj, 由于xj≥yj, 只需要考虑xi−d≤yj. 于是只要枚举xi然后用树状数组统计答案即可. 复杂度是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