• [HNOI2015] 接水果


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

    Solution

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

    • 如果 ((a,b)) 是直链,那么 (dfn[u] otin [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();
    }
    
    
  • 相关阅读:
    转载1
    转载
    WampServer的研究日记一
    第一期 花式自适应网页哪家强? 就选你啦
    缓动函数requestAnimationFrame用法
    原生js canvas 碰撞游戏的开发笔记2
    非常便利的前端模板smarty js 的使用
    原生js canvas 碰撞游戏的开发笔记
    Sublime Text 的研究日记
    面向对象设计模式(目录)
  • 原文地址:https://www.cnblogs.com/mollnn/p/12516901.html
Copyright © 2020-2023  润新知