zoukankan      html  css  js  c++  java
  • [2020多校联考]树

    Solution

    (没有定根就非常的离谱,后来告诉根直接就是 (1)

    先考虑链上怎么做,显然维护一个单调栈,求出第一个比当前数大的位置,然后倍增即可。再放在树上怎么做?依旧维护单调栈,但这次不能暴力地弹掉栈顶元素了,因为这样的复杂度是假的。因为单调栈有单调性,所以直接在单调栈内二分出单调栈弹得不能再弹的位置,然后修改 (top),继承答案。搜索回溯的时候再将栈还原即可。对于询问从 (u)(v) 初始智商为 (w) 能学习多少次,因只要 (pre[u][j]) 这个人的智商小于等于 (w) 就不会产生贡献,所以直接倍增地把这些点都跳过。最后不能跳了,跳到了 (u')。那么 (pre[u'][0]) 这个点智商一定比 (w) 大,从这个点之后就会产生贡献了。然后再次倍增,只要还在 (v) 的子树里。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 100007
    
    inline int read(){
        int x=0,flag=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    struct E{
        int next,to;
    }e[N<<1];
    int head[N],cnt=0;
    
    inline void add(int id,int to){
        e[++cnt]=(E){head[id],to};
        head[id]=cnt;
    }
    
    int sta[N],top=0,w[N],n,Q;
    int pre[N][18],dep[N],ans[N];
    
    inline bool Cmp(int x,int y){return w[x]>w[y];}
    void dfs(int u,int fa_u){
        int lt=top;
        top=lower_bound(sta+1,sta+1+lt,u,Cmp)-sta-1;
        pre[u][0]=sta[top++];
        ans[u]=ans[pre[u][0]]+1;
        for(int i=1;i<=17;i++)
            pre[u][i]=pre[pre[u][i-1]][i-1];
        int lw=sta[top],lpos=top;
        sta[top]=u;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==fa_u) continue;
            dep[v]=dep[u]+1,dfs(v,u);
        }
        top=lt,sta[lpos]=lw;
    }
    
    int main(){
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        n=read(),Q=read();
        for(int i=1;i<=n;i++) w[i]=read();
        for(int i=2;i<=n;i++){
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        dep[1]=1,dfs(1,0);
        while(Q--){
            int u=read(),v=read(),c=read();
            if(w[u]<=c){
                for(int i=17;~i;i--)
                    if(pre[u][i]&&w[pre[u][i]]<=c) u=pre[u][i];
                u=pre[u][0];
            }
            if(dep[u]<dep[v]) printf("0
    ");
            else{
                int tmp=u;
                for(int i=17;~i;i--)
                    if(dep[pre[u][i]]>=dep[v]) u=pre[u][i];
                printf("%d
    ",1+ans[tmp]-ans[u]);
            }
        }
    }
    
  • 相关阅读:
    第十周总结
    冲刺(四)
    冲刺(三)
    冲刺(二)
    冲刺(一)
    生成热词
    c#简单日志类
    WPF 后台代码 实现DynamicResource 绑定赋值
    WPF ListboxItem 双击事件 Command绑定
    mysql的命令行安装,忘记密码,密码重置问题
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14069303.html
Copyright © 2011-2022 走看看