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

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

时间:2023-02-07 18:35:43浏览次数:40  
标签:Distance return 剖分 int 边权 top dep ff id


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 didn't 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, you're asked to answer the number of edge whose value is no more than kk during the path between uu and vv."" If you can't 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. It's such a disgrace if DSM can't 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;
}

 

标签:Distance,return,剖分,int,边权,top,dep,ff,id
From: https://blog.51cto.com/u_14932227/6042624

相关文章

  • 长链剖分
    概述长链剖分通过把树剖成尽量长的多个链,高效地解决...我也不知道解决啥(长剖优化DP的东西在DP优化那边)。毕竟这个东西,不具备启发式分裂的复杂度。不过其还是有一......
  • 轻重链剖分
    概述轻重链剖分通过将树剖分为若干条重链和它们之间相连的轻边,将树上路径问题转化成序列问题。具体来讲,有很多树上路径问题本质上是把序列上的问题搬到了树上,此时我......
  • Android百度地图sdk 踩坑DistanceUtil.getDistance报错
    计算百度地图两个经纬度的距离一直崩溃,一直在报这个错误,一直在报找不到jni库函数的错误java.lang.UnsatisfiedLinkError:Noimplementationfoundforbooleancom.baid......
  • Hamming Distance汉明距离
    汉明距离是使用在数据传输差错控制编码里面的,汉明距离是一个概念,它表示两个(相同长度)字对应位不同的数量,我们以d(x,y)表示两个字x,y之间的汉明距离。对两个字符串进行异或运算,......
  • 负边权最短路
    负边权Bellmanford接下来看几道栗子吧给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。请你求出从1号点到n号点的最多经过k条边的最短......
  • 关于长链剖分的数组实现 | CF1009F Dominant Indices
    请容许我不理解一下为什么这题题解几乎全都是指针实现/kk其实长链剖分是可以直接用数组来写的。考虑朴素DP。设\(f_{u,i}\)表示以点\(u\)为根的子树中与点\(u\)距......
  • 树链剖分
    dfs序与树链剖分dfs序比如dfs序为:ABDGHICEJF时间戳时间戳即dfs每次访问到每个节点的时间,时间从1开始累加比如上图时间戳为用处把树强行搞成连续的......
  • Codeforces-343D Water Tree(树链剖分)
    Description:MadscientistMikehasconstructedarootedtree,whichconsistsof n vertices.Eachvertexisareservoirwhichcanbeeitheremptyorfilledw......
  • SPOJ375--Query on a tree(树链剖分)
    Description:Youaregivenatree(anacyclicundirectedconnectedgraph)with N nodes,andedgesnumbered1,2,3...N-1.Wewillaskyoutoperfromsomeins......
  • 树链剖分
    “在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。树链剖分......