1 条题解

  • 0
    @ 2025-8-24 21:46:52

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Owen_codeisking
    前OIer/ACMer/柚子厨/酒姬民

    搬运于2025-08-24 21:46:52,当前版本为作者最后更新于2018-12-23 19:17:39,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    从下午三点开此题调到到七点,AA 掉此题的感觉真的是太爽了!!!

    而且我觉得这道题对于练整体二分非常的好,就是写的人有点少。

    不过为什么盘子是水果的子路径才是接住啊。。。不应该盘子比水果大的嘛。。。

    我们将此路径覆盖分两类讨论:

    不妨令 stx<styst_x<st_y

    1、LCA(x,y)=xLCA(x,y)=x

    那么我们发现其实路径一个端点在 [sty,edy][st_y,ed_y],另一个不在除 x,yx,yx>yx->y 的路径上的点 zz 的子树内就行了,即 [1,stz1] or [edz+1,n][1,st_z-1]\ or\ [ed_z+1,n]。其实用树剖一直向上跳,跳到离 xx 最近的点且其子树内包含 yy 就是 zz 了。

    2、LCA(x,y)xLCA(x,y)\not =x

    那么一个点在 [stx,edx][st_x,ed_x],另一个点在 [sty,edy][st_y,ed_y] 就行了

    发现可以做一遍扫描线,直接暴力树套树。在内层线段树动态开点,然后二分答案,log2n\log^2 n 验证,时间复杂度 O(nlog3n)O(n\log^3n),空间复杂度 O(nlog2n)O(n\log^2 n)

    那有没有更好的解法呢?发现没有离线,第 kk 小,

    我们可以请出我们的整体二分!

    然后正解就是扫描线+整体二分了。把矩形差分一下,然后区间加,单点查,套一个差分的树状数组就好了。时间复杂度 O(nlog2n)O(n\log^2 n),空间复杂度 O(n)O(n)

    Code Below:Code\ Below:

    #include <bits/stdc++.h>
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int maxn=40000+10;
    int n,m,Q,c[maxn],ans[maxn],mp[maxn],lim,head[maxn],to[maxn<<1],nxt[maxn<<1],tot,cnt;
    int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn],st[maxn],ed[maxn],tim;
    
    struct Query{
        int op,x,l,r,k,v,id;
    }q[maxn*5],q1[maxn*5],q2[maxn*5];
    
    bool cmp(Query a,Query b){
        if(a.x!=b.x) return a.x<b.x;
        return a.op<b.op;
    }
    
    inline void read(int &x){
        x=0;int f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        if(f==-1) x=-x;
    }
    void print(int x){
        if(x<0){putchar('-');x=-x;}
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    
    inline void upd(int x,int y){
        for(;x<=n;x+=lowbit(x)) c[x]+=y;
    }
    inline int sum(int x){
        int ans=0;
        for(;x;x-=lowbit(x)) ans+=c[x];
        return ans;
    }
    
    inline void add(int x,int y){
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    
    void dfs1(int x,int f){
        fa[x]=f;siz[x]=1;
        dep[x]=dep[f]+1;
        int maxson=-1;
        for(int i=head[x],y;i;i=nxt[i]){
            y=to[i];
            if(y==f) continue;
            dfs1(y,x);
            siz[x]+=siz[y];
            if(siz[y]>maxson){
                maxson=siz[y];
                son[x]=y;
            }
        }
    }
    
    void dfs2(int x,int topf){
        top[x]=topf;
        st[x]=++tim;
        if(son[x]) dfs2(son[x],topf);
        for(int i=head[x],y;i;i=nxt[i]){
            y=to[i];
            if(y==fa[x]||y==son[x]) continue;
            dfs2(y,y);
        }
        ed[x]=tim;
    }
    
    int LCA(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        return x;
    }
    
    int getson(int x,int y){
        while(top[x]!=top[y]){
            if(fa[top[x]]==y) return top[x];
            x=fa[top[x]];
        }
        return son[y];
    }
    
    void solve(int L,int R,int l,int r){
        if(L>R) return ;
        if(l==r){
            for(int i=L;i<=R;i++)
                if(q[i].op==2) ans[q[i].id]=mp[l];
            return ;
        }
        int mid=(l+r)>>1,cnt1=0,cnt2=0,val;
        for(int i=L;i<=R;i++){
            if(q[i].op==1){
                if(q[i].k<=mid){
                    upd(q[i].l,q[i].v);upd(q[i].r+1,-q[i].v);
                    q1[++cnt1]=q[i];
                }
                else q2[++cnt2]=q[i];
            }
            else {
                val=sum(q[i].l);
                if(val>=q[i].k) q1[++cnt1]=q[i];
                else q[i].k-=val,q2[++cnt2]=q[i];
            }
        }
        for(int i=1;i<=cnt1;i++) q[L+i-1]=q1[i];
        for(int i=1;i<=cnt2;i++) q[L+i+cnt1-1]=q2[i];
        solve(L,L+cnt1-1,l,mid);solve(L+cnt1,R,mid+1,r);
    }
    
    int main()
    {
        read(n),read(m),read(Q);
        int x,y,z,l,r,k,lca;
        for(int i=1;i<n;i++){
            read(x),read(y);
            add(x,y);add(y,x);
        }
        dfs1(1,0);dfs2(1,1);
        for(int i=1;i<=m;i++){
            read(x),read(y),read(k);mp[i]=k;
            if(st[x]>st[y]) swap(x,y);
            lca=LCA(x,y);
            if(lca==x){
                z=getson(y,x);
                if(st[z]>1){
                    q[++cnt]=(Query){1,1,st[y],ed[y],k,1,0};
                    q[++cnt]=(Query){1,st[z],st[y],ed[y],k,-1,0};
                }
                if(ed[z]<n){
                    q[++cnt]=(Query){1,st[y],ed[z]+1,n,k,1,0};
                    q[++cnt]=(Query){1,ed[y]+1,ed[z]+1,n,k,-1,0};
                }
            }
            else {
                q[++cnt]=(Query){1,st[x],st[y],ed[y],k,1,0};
                q[++cnt]=(Query){1,ed[x]+1,st[y],ed[y],k,-1,0};
            }
        }
        sort(mp+1,mp+m+1);
        lim=unique(mp+1,mp+m+1)-mp-1;
        for(int i=1;i<=cnt;i++) q[i].k=lower_bound(mp+1,mp+lim+1,q[i].k)-mp;
        for(int i=1;i<=Q;i++){
            read(x),read(y),read(k);
            if(st[x]>st[y]) swap(x,y);
            q[++cnt]=(Query){2,st[x],st[y],0,k,0,i};
        }
        sort(q+1,q+cnt+1,cmp);
        solve(1,cnt,1,lim);
        for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
        return 0;
    }
    
    • 1

    信息

    ID
    2315
    时间
    6000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者