2019年ICPC南昌网络赛 J. Distance on the tree(树链剖分+主席树 查询路径边权第k大)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019年ICPC南昌网络赛 J. Distance on the tree(树链剖分+主席树 查询路径边权第k大)相关的知识,希望对你有一定的参考价值。


DSM(Data Structure Master) once learned about tree when he was preparing for NOIP(National Olympiad in Informatics in Provinces) in Senior High School. So when in Data Structure Class in College, he is always absent-minded about what the teacher says.

The experienced and knowledgeable teacher had known about him even before the first class. However, she didnt wish an informatics genius would destroy himself with idleness. After she knew that he was so interested in ACM(ACM International Collegiate Programming Contest), she finally made a plan to teach him to work hard in class, for knowledge is infinite.

This day, the teacher teaches about trees." A tree with nn nodes, can be defined as a graph with only one connected component and no cycle. So it has exactly n-1n−1 edges..." DSM is nearly asleep until he is questioned by teacher. " I have known you are called Data Structure Master in Graph Theory, so here is a problem. "" A tree with nn nodes, which is numbered from 11 to nn. Edge between each two adjacent vertexes uu and vv has a value w, youre asked to answer the number of edge whose value is no more than kk during the path between uu and vv."" If you cant solve the problem during the break, we will call you DaShaMao(Foolish Idiot) later on."

The problem seems quite easy for DSM. However, it can hardly be solved in a break. Its such a disgrace if DSM cant solve the problem. So during the break, he telephones you just for help. Can you save him for his dignity?

Input

In the first line there are two integers n,mn,m, represent the number of vertexes on the tree and queries(2 \\le n \\le 10^5,1 \\le m \\le 10^52≤n≤105,1≤m≤105)

The next n-1n−1 lines, each line contains three integers u,v,wu,v,w, indicates there is an undirected edge between nodes uu and vv with value ww. (1 \\le u,v \\le n,1 \\le w \\le 10^91≤u,v≤n,1≤w≤109)

The next mm lines, each line contains three integers u,v,ku,v,k , be consistent with the problem given by the teacher above. (1 \\le u,v \\le n,0 \\le k \\le 10^9)(1≤u,v≤n,0≤k≤109)

Output

For each query, just print a single line contains the number of edges which meet the condition.

样例输入1复制

3 3
1 3 2
2 3 7
1 3 0
1 2 4
1 2 7

样例输出1复制

0
1
2

样例输入2复制

5 2
1 2 1000000000
1 3 1000000000
2 4 1000000000
3 5 1000000000
2 3 1000000000
4 5 1000000000

样例输出2复制

2
4

题意:

你一棵树,n个节点(n<1e5),m次询问(m<1e5),每次询问<u,v,k>

即,从节点u到节点v的路上,有多少条边的长度小于等于k

分析:

树链剖分+主席树

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pb(x) push_back(x)
#define N 200005
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
//查询u->v的路径中有多少条边的权值小于w
//根节点赋值无穷大,其他的边将 边权赋给下顶点。

vector<int>V;
struct node

int to,nt,w;
g[N*3];
struct Q

int x,y,w;
q[N];

int tot;
int head[N];
void addedg(int x,int y,int w)

g[tot].to=y;
g[tot].nt=head[x];
g[tot].w=w;
head[x]=tot++;

int sz[N],son[N],dep[N],num[N];//子树大小,重儿子,深度,dfs序为id对应的节点。
int fa[N],top[N],val[N],rnk[N];//父节点,链顶,权值,dfs序
void dfs1(int u,int f,int de)//第一次dfs出dep fa 和重儿子。

dep[u]=de;
fa[u]=f;
sz[u]=1;
int mx=-1;
for(int i=head[u]; i+1; i=g[i].nt)

int v=g[i].to;
if(v==f)
continue;
val[v]=g[i].w;
dfs1(v,u,de+1);
sz[u]+=sz[v];
if(sz[v]>mx)
mx=sz[v],son[u]=v;


int id;
void dfs2(int u,int Top)//第二次优先走重儿子,将树上的链展开。

top[u]=Top;
rnk[u]=++id;
num[id]=u;
if(!son[u])
return ;
dfs2(son[u],Top);
for(int i=head[u]; i+1; i=g[i].nt)

int v=g[i].to;
if(v==fa[u]||v==son[u])
continue;
dfs2(v,v);



int cnt;
int sum[N*36],ls[N*36],rs[N*36],T[N*36];//主席树部分
void build(int &rt,int l,int r)

rt=++cnt;
sum[rt]=0;
if(l==r)
return ;
int m=(l+r)>>1;
build(ls[rt],l,m);
build(rs[rt],m+1,r);


void upd(int &now,int pre,int l,int r,int pos)

now=++cnt;
sum[now]=sum[pre]+1;
ls[now]=ls[pre],rs[now]=rs[pre];
if(l==r)
return ;
int m=(l+r)>>1;
if(pos<=m)
upd(ls[now],ls[pre],l,m,pos);
else
upd(rs[now],rs[pre],m+1,r,pos);


int ask(int now,int pre,int l,int r,int pos)

if(r<=pos)
return sum[now]-sum[pre];
int m=(l+r)>>1;
if(pos<=m)
return ask(ls[now],ls[pre],l,m,pos);
else
return ask(ls[now],ls[pre],l,m,pos)+ask(rs[now],rs[pre],m+1,r,pos);


int SZ;
void init(int n,int m)//将询问和原始的边权离散化

for(int i=2; i<=n; i++)
val[i]=lower_bound(V.begin(),V.end(),val[i])-V.begin()+1;
for(int i=1; i<=m; i++)
q[i].w=lower_bound(V.begin(),V.end(),q[i].w)-V.begin()+1;

SZ=V.size()+100;
build(T[0],1,SZ);
val[1]=V.size()+5;
for(int i=1; i<=n; i++)
upd(T[i],T[i-1],1,SZ,val[num[i]]);


int query(int u,int v,int pos)//对路径的查询,基于边权。

int ans=0;
while(top[u]!=top[v])

if(dep[top[u]]<dep[top[v]])
swap(u,v);
ans+=ask(T[rnk[u]],T[rnk[top[u]]-1],1,SZ,pos);//这里要把top[u]算进来,所以要减一
u=fa[top[u]];

if(dep[u]<dep[v])
swap(u,v);
ans+=ask(T[rnk[u]],T[rnk[v]],1,SZ,pos);//这里v不能减一,因为v不能算进来(v点所代表的边权不是要求路径上的)。
return ans;


int main()

int n,m;
scanf("%d",&n);scanf("%d",&m);
memset(head,-1,sizeof(head));
for(int i=1; i<n; i++)

int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addedg(x,y,w);
addedg(y,x,w);
V.pb(w);

for(int i=1; i<=m; i++)

scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].w);
V.pb(q[i].w);

sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());

dfs1(1,0,1);
dfs2(1,1);

init(n,m);
for(int i=1; i<=m; i++)
printf("%d\\n",query(q[i].x,q[i].y,q[i].w));

 

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
#define mp(x,y) make_pair(x,y)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N = 100005;
const int maxn = 100005;
int n,m;
int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N]; //top 近期的重链父节点
int num;
vector<pair<int,int> > v[N];
int a[N];
struct nod

int id,v,fg;
int x,y;
bool operator<(nod aa)const

return v<aa.v||(v==aa.v&&fg<aa.fg);

q[maxn<<1];
int as[maxn];
struct tree

int x,y,val;
void read()
scanf("%d%d%d",&x,&y,&val);

;
tree e[N];
void dfs1(int u, int f, int d)
dep[u] = d;
siz[u] = 1;
son[u] = 0;
fa[u] = f;
for (int i = 0; i < v[u].size(); i++)
int ff = v[u][i].first;
if (ff == f) continue;
q[ff].v=v[u][i].second;
q[ff].id=ff;
q[ff].x=ff;
q[ff].y=u;
dfs1(ff, u, d + 1);
siz[u] += siz[ff];
if (siz[son[u]] < siz[ff])
son[u] = ff;


void dfs2(int u, int tp)
top[u] = tp;
id[u] = ++num;
if (son[u]) dfs2(son[u], tp);
for (int i = 0; i < v[u].size(); i++)
int ff = v[u][i].first;
if (ff == fa[u] || ff == son[u]) continue;
dfs2(ff, ff);



int lb(int x)return x&(-x);
void add(int x,int v)

while(x<N)

a[x]+=v;
x+=lb(x);


int query(int x)

int sum=0;
while(x)

sum+=a[x];
x-=lb(x);

return sum;



int Yougth(int u, int v)
//cout<<"OK";
int tp1 = top[u], tp2 = top[v];
int ans = 0;
while (tp1 != tp2)
//printf("YES\\n");
if (dep[tp1] < dep[tp2])
swap(tp1, tp2);
swap(u, v);

ans+=query(id[u])-query(id[tp1]-1);
u = fa[tp1];
tp1 = top[u];

if (u == v) return ans;
if (dep[u] > dep[v]) swap(u, v);
ans += query(id[v])-query(id[son[u]]-1);
//cout<<"OOOOK"<<endl;;
return ans;

void Clear(int n)

for(int i=0;i<=n;i++)

a[i]=0;
v[i].clear();


int main()

int T,cas=1;
scanf("%d%d",&n,&m);

for(int i=1;i<n;i++)

e[i].read();
q[i].fg=0;
v[e[i].x].push_back(mp(e[i].y,e[i].val));
v[e[i].y].push_back(mp(e[i].x,e[i].val));

num = 0;
q[1].v=inf;
q[1].id=1;
q[1].x=1;
q[1].y=1;
dfs1(1,0,1);
//rep(i,1,n)
//cout<<q[i].fg<<" "<<q[i].x<<endl;
dfs2(1,1);
for (int i = 1; i < n; i++)
if (dep[e[i].x] < dep[e[i].y]) swap(e[i].x, e[i].y);
val[id[e[i].x]] = e[i].val;

rep(i,1,m)

scanf("%d%d%d",&q[i+n].x,&q[i+n].y,&q[i+n].v);
q[i+n].id=i+n;
q[i+n].fg=1;

//cout<<"*"<<endl;
sort(q+1,q+n+m+1);
rep(i,1,n+m)

//cout<<i<<"*"<<q[i].fg<<" "<<q[i].id<<" "<<q[i].x;
if(q[i].fg)

as[q[i].id-n]=Yougth(q[i].x,q[i].y);

else

int u=q[i].x;int v=q[i].y;
int tp1 = top[u], tp2 = top[v];
if (dep[tp1] < dep[tp2])
swap(tp1, tp2);
swap(u, v);

//cout<<u<<" "<<id[u]<<endl;
add(id[u],1);

//cout<<"*"<<endl;;

rep(i,1,m)
printf("%d\\n",as[i]);
//Clear(n);

return 0;

 

以上是关于2019年ICPC南昌网络赛 J. Distance on the tree(树链剖分+主席树 查询路径边权第k大)的主要内容,如果未能解决你的问题,请参考以下文章

2019 ICPC 南昌网络赛

2019ICPC南昌网络赛总结

2019icpc南昌网络赛

2019南昌icpc网络赛 I题 分块套BIT

ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

2019 南昌网络赛icpc I题 cdq分治或分块