[HNOI2015] 接水果 - DFS序,扫描线,线段树套线段树

给定一棵树,树上有 \(p\) 条路径,分别有权值 \(c_i\)。给定 \(q\) 个询问,每个询问给定一条路径,问所有是询问路径的子路径的树上路径中,权值第 \(k\) 小的是多少。\(n \leq 40000\)

Solution

考虑一条给定路径 \((a,b)\) 是询问路径 \((u,v)\) 子路径的条件,不妨设 \(a,u\) 各自是 DFS 序较小的那个

  • 如果 \((a,b)\) 是直链,那么 \(dfn[u] \notin [dfn[x],fin[x]], dfn[v]\in[dfn[b],fin[b]]\),其中 \(x\)\(a\)\(b\) 走遇到的第一个点,这个可以利用倍增求出
  • 如果 \((a,b)\) 是弯链,那么 \(dfn[u]\in[dfn[a],fin[a]], dfn[v]\in[dfn[b],fin[b]]\)

于是问题转化为二维平面上有若干个矩形,给定 \(q\) 个询问点,每次问覆盖这个点的所有矩形中第 \(k\) 小权值的矩形权值是多少

如果没有这个第 \(k\) 的要求,直接扫描线,线段树维护即可

现在多了 \(k\) 的要求,于是线段树套线段树即可,外层维护下标,内层维护权值

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;
const int M = 2e7;
const int lim = 1e9;

int n,p,q,a[N],b[N],c[N],u[N],v[N],k[N],fa[N][19],dep[N],t1,t2,t3;
int dfn[N],fin[N],ind,nrect,ans[N];
vector <int> g[N];

struct point {
    int x,y,k;
} pt[N];

struct rect {
    int x1,y1,x2,y2,v;
} rec[N];

struct query {
    int x,t,k,id;
};

struct event {
    int l,r,t,v;
};

vector <query> que[N];
vector <event> evp[N],evn[N];

void dfs(int p) {
    dfn[p]=++ind;
    for(int i=1;i<19;i++) fa[p][i]=fa[fa[p][i-1]][i-1];
    for(int q:g[p]) if(dfn[q]==0) dep[q]=dep[p]+1, fa[q][0]=p, dfs(q);
    fin[p]=ind;
}

int getpoint(int p,int q) {
    if(dep[p]<dep[q]) swap(p,q);
    for(int i=18;i>=0;--i) if(dep[fa[p][i]]>dep[q]) p=fa[p][i];
    return p;
}

namespace iseg {
    int ch[M][2],a[M],ind;
    void modify(int p,int l,int r,int pos,int val) {
        a[p]+=val;
        if(l<r) {
            if(pos<=(l+r)/2) {
                if(ch[p][0]==0) ch[p][0]=++ind;
                modify(ch[p][0],l,(l+r)/2,pos,val);
            }
            else {
                if(ch[p][1]==0) ch[p][1]=++ind;
                modify(ch[p][1],(l+r)/2+1,r,pos,val);
            }
        }
    }
    int newnode() {
        return ++ind;
    }
    int query(int p,int l,int r,int ql,int qr) {
        if(l>qr || r<ql || p==0) return 0;
        if(l>=ql&&r<=qr) return a[p];
        return query(ch[p][0],l,(l+r)/2,ql,qr)+query(ch[p][1],(l+r)/2+1,r,ql,qr);
    }
}

namespace oseg {
    int a[M];
    void modify(int p,int l,int r,int ql,int qr,int pos,int val) {
        if(l>qr || r<ql) return;
        if(l>=ql&&r<=qr) {
            if(a[p]==0) a[p]=iseg::newnode();
            iseg::modify(a[p],1,lim,pos,val);
        }
        else {
            modify(p*2,l,(l+r)/2,ql,qr,pos,val);
            modify(p*2+1,(l+r)/2+1,r,ql,qr,pos,val);
        }
    }
    int query(int p,int l,int r,int x,int vl,int vr) {
        int tmp = iseg::query(a[p],1,lim,vl,vr);
        if(l==r) {
            return tmp;
        }
        else {
            if(x<=(l+r)/2) return tmp + query(p*2,l,(l+r)/2,x,vl,vr);
            else return tmp + query(p*2+1,(l+r)/2+1,r,x,vl,vr);
        }
    }
}

namespace seq {
    vector <int> a[N];
    void modify(int ql,int qr,int pos) {
        oseg::modify(1,1,n,ql,qr,pos,1);
    }
    void erase(int ql,int qr,int pos) {
        oseg::modify(1,1,n,ql,qr,pos,-1);
    }
    int query(int x,int vl,int vr) {
        return oseg::query(1,1,n,x,vl,vr);
    }
    int kth(int x,int k) {
        int l=0,r=1e9;
        while(l<r) {
            int mid=(l+r)/2;
            if(query(x,1,mid)>=k) r=mid;
            else l=mid+1;
        }
        return l;
    }
}

void read() {
    ios::sync_with_stdio(false);
    cin>>n>>p>>q;
    for(int i=1;i<n;i++) {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    for(int i=1;i<=p;i++) {
        cin>>a[i]>>b[i]>>c[i];
    }
    for(int i=1;i<=q;i++) {
        cin>>u[i]>>v[i]>>k[i];
    }
    dfs(1);
}

void make() {
    for(int i=1;i<=p;i++) {
        if(dfn[a[i]]>dfn[b[i]]) swap(a[i],b[i]);
        if(dfn[a[i]]<=dfn[b[i]] && fin[a[i]]>=dfn[b[i]]) {
            a[i]=getpoint(a[i],b[i]);
            rec[++nrect]={1,dfn[b[i]],dfn[a[i]]-1,fin[b[i]],c[i]};
            rec[++nrect]={fin[a[i]]+1,dfn[b[i]],n,fin[b[i]],c[i]};
        }
        else {
            rec[++nrect]={dfn[a[i]],dfn[b[i]],fin[a[i]],fin[b[i]],c[i]};
        }
    }
    for(int i=1;i<=q;i++) {
        if(dfn[u[i]]>dfn[v[i]]) swap(u[i],v[i]);
        pt[i]={dfn[u[i]],dfn[v[i]],k[i]};
    }
    for(int i=1;i<=nrect;i++) {
        if(rec[i].x1>rec[i].x2 || rec[i].y1>rec[i].y2) continue;
        evp[rec[i].y1].push_back({rec[i].x1,rec[i].x2,rec[i].y1,rec[i].v});
        evn[rec[i].y2].push_back({rec[i].x1,rec[i].x2,rec[i].y2,rec[i].v});
        evp[rec[i].x1].push_back({rec[i].y1,rec[i].y2,rec[i].x1,rec[i].v});
        evn[rec[i].x2].push_back({rec[i].y1,rec[i].y2,rec[i].x2,rec[i].v});
    }
    for(int i=1;i<=q;i++) {
        que[pt[i].y].push_back({pt[i].x,pt[i].y,pt[i].k,i});
    }
}

void solve() {
    for(int i=1;i<=n;i++) {
        for(event e:evp[i]) {
            seq::modify(e.l,e.r,e.v);
        }
        for(query q:que[i]) {
            ans[q.id]=seq::kth(q.x,q.k);
        }
        for(event e:evn[i]) {
            seq::erase(e.l,e.r,e.v);
        }
    }
}

void print() {
    for(int i=1;i<=q;i++) cout<<ans[i]<<endl;
}

signed main() {
    read();
    make();
    solve();
    print();
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12516901.html