Luogu3242 [HNOI2015]接水果

Luogu3242 [HNOI2015]接水果

题面:[洛谷](3242 [HNOI2015]接水果)

解析

(dfs)序的套路应用,记(dfn[i])表示点(i)(dfs)序,(low[i])表示以点(i)为根的子树中最大的(dfs)序。考虑对于一条路径((x,y)(dfn[x] leq dfn[y])),能够包含它的路径的两个端点(a,b(dfn[a] leq dfn[b]))一定满足以下条件:
(1.LCA(x,y)=x),记(z)(y)对应的(x)的儿子,那么有(1 leq dfn[a] leq dfn[z]-1,dfn[y] leq dfn[b] leq low[y])或者(dfn[y] leq dfn[a] leq low[y],low[z]+1 leq dfn[b] leq n)
(2.LCA(x,y)!=x),那么有(dfn[x] leq dfn[a] leq low[x],dfn[y] leq dfn[b] leq low[y])
那么问题就转化为计算一个点被多少矩阵覆盖,扫描线加上整体二分即可。

代码


// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 40005
using namespace std;
const int nlog=15;
inline int In(){
    char c=getchar(); int x=0,ft=1;
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
    for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
    return x*ft;
}
int n,P,Q,h[N],e_tot=0;
struct E{ int to,nex; }e[N<<1];
inline void add(int u,int v){
    e[++e_tot]=(E){v,h[u]}; h[u]=e_tot;
    e[++e_tot]=(E){u,h[v]}; h[v]=e_tot;
}
int d[N],sz[N],dfn[N],fa[N][nlog+5],dfs_clock=0;
void dfs(int u,int pre,int dep){
    d[u]=dep; dfn[u]=++dfs_clock; fa[u][0]=pre; sz[u]=1;
    for(int i=1;i<=nlog;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=h[u],v;i;i=e[i].nex){
        v=e[i].to; if(v==pre) continue;
        dfs(v,u,dep+1); sz[u]+=sz[v];
    }
}
inline int LCA(int x,int y,int& u){
    if(d[x]<d[y]) swap(x,y);
    int delta=d[x]-d[y]-1;
    for(int i=nlog;~i;--i) if(delta&(1<<i)) x=fa[x][i];
    if(fa[x][0]==y) return fa[u=x][0];
    else x=fa[x][0];
    for(int i=nlog;~i;--i)
    if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[u=x][0];
}
int id[N],qc=0;
struct Que{ int pos,l,r,d,val; }q[N*5];
inline bool cmp(int a,int b){
    return q[a].pos==q[b].pos?q[a].r>q[b].r:q[a].pos<q[b].pos;
}
inline void insert1(int x,int y,int C){
    int u,lca=LCA(x,y,u);
    if(dfn[x]>dfn[y]) swap(x,y);
    if(lca==x){
        if(dfn[u]>1){
            q[++qc]=(Que){1,dfn[y],dfn[y]+sz[y]-1,1,C};
            q[++qc]=(Que){dfn[u],dfn[y],dfn[y]+sz[y]-1,-1,C};
        }
        if(dfn[u]+sz[u]<=n){
            q[++qc]=(Que){dfn[y],dfn[u]+sz[u],n,1,C};
            q[++qc]=(Que){dfn[y]+sz[y],dfn[u]+sz[u],n,-1,C};
        }
    }
    else{
        q[++qc]=(Que){dfn[x],dfn[y],dfn[y]+sz[y]-1,1,C};
        q[++qc]=(Que){dfn[x]+sz[x],dfn[y],dfn[y]+sz[y]-1,-1,C};
    }
}
inline void insert2(int x,int y,int C,int p){
    if(dfn[x]>dfn[y]) swap(x,y);
    q[++qc]=(Que){dfn[x],dfn[y],0,C,0};
}
int sum[N];
inline int LB(int x){
    return x&(-x);
}
inline void Add(int x,int C){
    for(int i=x;i<=n;i+=LB(i)) sum[i]+=C;
}
inline int Sum(int x){
    int res=0;
    for(int i=x;i;i-=LB(i)) res+=sum[i];
    return res;
}
inline void Update(int L,int R,int C){
    Add(L,C); Add(R+1,-C);
}
int ans[N*5],t1[N*5],t2[N*5];
void Solve(int l,int r,int ql,int qr){
    if(ql>qr) return;
    if(l==r){
        for(int i=ql;i<=qr;++i) ans[id[i]]=l; return;
    }
    int mid=(l+r)>>1,c1=0,c2=0;
    for(int i=ql,u;i<=qr;++i){
        u=id[i];
        if(q[u].r){
            if(q[u].val<=mid) Update(q[u].l,q[u].r,q[u].d),t1[++c1]=u;
            else t2[++c2]=u;
        }
        else{
            int S=Sum(q[u].l);
            if(q[u].d<=S) t1[++c1]=u;
            else q[u].d-=S,t2[++c2]=u;
        }
    }
    for(int i=ql,u;i<=qr;++i)
    if(q[u=id[i]].r&&q[u].val<=mid) Update(q[u].l,q[u].r,-q[u].d);
    for(int i=1;i<=c1;++i) id[ql+i-1]=t1[i];
    for(int i=1;i<=c2;++i) id[ql+c1+i-1]=t2[i];
    Solve(l,mid,ql,ql+c1-1); Solve(mid+1,r,ql+c1,qr);
}
int main(){
    n=In(); P=In(); Q=In();
    for(int i=1;i<n;++i) add(In(),In());
    dfs(1,0,0);
    for(int i=1,a,b,c;i<=P;++i){
        a=In(); b=In(); c=In(); insert1(a,b,c);
    }
    int sav=qc;
    for(int i=1,u,v,k;i<=Q;++i){
        u=In(); v=In(); k=In(); insert2(u,v,k,i);
    }
    for(int i=1;i<=qc;++i) id[i]=i;
    sort(id+1,id+1+qc,cmp);
    Solve(0,1e9,1,qc);
    for(int i=1;i<=Q;++i) printf("%d
",ans[i+sav]);
    return 0;
}

原文地址:https://www.cnblogs.com/pkh68/p/10574968.html