南昌网络赛 Distance on the tree 主席树+树剖 (给一颗树,m次查询ui->vi这条链中边权小于等于ki的边数。)...

https://nanti.jisuanke.com/t/38229

题目:

给一颗树,m次查询ui->vi这条链中边权小于等于ki的边数。

 

 
#include <bits/stdc++.h>
#define mid (l+r>>1)
#define lson (o<<1)
#define rson (o<<1|1)
#define all(x) (x).begin(),(x).end()
using namespace std;
const int N = 2e5+1000;
vector<int>nxt[N],len[N];
int fa[N],deep[N],id[N],siz[N],son[N],tot,s[N],top[N],ss[N];
int n,m;
int SIZ;
 
struct TREE{
    int l,r,x;
}tree[N*20];
int rk[N],Tot,rt[N];
void insert(int &o,int l,int r,int data){
    tree[++Tot] = tree[o];
    o = Tot;
    tree[o].x++;
    if(l==r) return ;
    if(mid>=data) insert(tree[o].l,l,mid,data);
    else insert(tree[o].r,mid+1,r,data);
}
int query(int lo,int ro,int l,int r,int h,int t){
    if(l>=h&&r<=t) return tree[ro].x-tree[lo].x;
    int ans = 0;
    if(mid>=h) ans += query(tree[lo].l,tree[ro].l,l,mid,h,t);
    if(mid<t) ans += query(tree[lo].r,tree[ro].r,mid+1,r,h,t);
    return ans;
}
 
void dfs(int u,int f) {
    deep[u] = deep[f]+1;
    son[u] = 0;
    siz[u] = 1;
    fa[u] = f;
    for(int i = 0; i < nxt[u].size(); i++) {
        int v = nxt[u][i];
        int w = len[u][i];
        if(v==f) continue;
        s[v] = w;
        dfs(v,u);
        siz[u] += siz[v];
        if(siz[son[u]]<siz[v]) son[u] = v;
    }
}
void dfs2(int u,int t) {
    id[u] = ++tot;
    ss[id[u]] = s[u];
    top[u] = t;
    if(son[u]) dfs2(son[u],t);
    for(auto v:nxt[u]) {
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}
int Query(int u,int v,int x) {
    int tu = top[u];
    int tv = top[v];
    int ans = 0;
    while(tu!=tv) {
        if(deep[tu]<deep[tv]) {
            swap(u,v);
            swap(tu,tv);
        }
        ans += query(rt[id[tu]-1],rt[id[u]],1,SIZ,1,x);
        u = fa[tu];
        tu = top[u];
    }
    if(u==v) return ans;
    if(id[u]>id[v]) swap(u,v);
    ans += query(rt[id[u]],rt[id[v]],1,SIZ,1,x);
    return ans;
}
 
struct Q{
    int u, v, w;
}Q[N];
vector<int> k;
int main() {
    scanf("%d%d",&n,&m);
    for(int i = 1; i < n; i++) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        nxt[u].push_back(v);
        nxt[v].push_back(u);
        len[u].push_back(w);
        len[v].push_back(w);
        k.push_back(w);
    }
    for(int i = 1; i <= m; i++) {
        int u, v, x;
        scanf("%d%d%d",&Q[i].u,&Q[i].v,&Q[i].w);
        k.push_back(Q[i].w);
    }
    sort(all(k));
    k.erase(unique(all(k)),k.end());
    SIZ = k.size()+10;
    dfs(1,0);
    dfs2(1,1);
    rt[0] = 0;
    tree[0].l = tree[0].r = tree[0].x = 0;
    for(int i = 1; i <= n; i++) {
        rt[i] = rt[i-1];
        int x = lower_bound(all(k),ss[i])-k.begin()+1;
        insert(rt[i],1,SIZ,x);
    }
    for(int i = 1; i <= m; i++) {
        int x = lower_bound(all(k),Q[i].w)-k.begin()+1;
        printf("%d\n",Query(Q[i].u,Q[i].v,x));
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/shuaihui520/p/10751090.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值