zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    改变页面选择文字颜色和背景颜色----selection伪元素
    中文版Chrome浏览器不支持12px以下字体的解决方案
    css直接写出小三角
    解决ie6 闪动的问题
    去掉firefox点击按钮时的虚线边框
    去除input在谷歌下的focus效果
    文本输入框的两种div+css的写法
    常用排序算法
    wtforms
    Flask
  • 原文地址:https://www.cnblogs.com/pkh68/p/10574968.html
Copyright © 2011-2022 走看看