zoukankan      html  css  js  c++  java
  • HDU 5877 Weak Pair

    $dfs$序,线段树。

    可以统计每一个节点作为$root$的子树上对答案的贡献,可以将树转换成序列。问题就变成了一段区间上求小于等于某个值的数有几个。用线段树记录排好序之后的区间序列,询问的时候,属于询问区间的每个节点二分一下统计答案即可。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-6;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c=getchar(); x=0;
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) {x=x*10+c-'0'; c=getchar();}
    }
    
    const int maxn=100010;
    int T,n,h[maxn],sz,r[maxn],root;
    LL k,v[maxn];
    struct Edge { int u,v,nx; }e[maxn];
    LL a[2*maxn],L[2*maxn],R[2*maxn];
    vector<int>s[8*maxn];
    
    void add(int u,int v)
    {
        e[sz].u=u; e[sz].v=v;
        e[sz].nx=h[u]; h[u]=sz++;
    }
    
    void dfs(int x)
    {
        sz++; a[sz]=v[x]; L[x]=sz;
        for(int i=h[x];i!=-1;i=e[i].nx) dfs(e[i].v);
        sz++; a[sz]=v[x]; R[x]=sz;
    }
    
    void build(int l,int r,int rt)
    {
        if(l==r) { s[rt].push_back(a[l]); return; }
        int m=(l+r)/2; build(l,m,2*rt); build(m+1,r,2*rt+1);
    
        int sum=0,p1=0,p2=0;
        while(sum<r-l+1)
        {
            if(p1<s[2*rt].size()&&p2<s[2*rt+1].size())
            {
                if(s[2*rt][p1]<s[2*rt+1][p2]) s[rt].push_back(s[2*rt][p1]), p1++;
                else s[rt].push_back(s[2*rt+1][p2]), p2++;
            }
            else if(p1<s[2*rt].size()) s[rt].push_back(s[2*rt][p1]), p1++;
            else s[rt].push_back(s[2*rt+1][p2]), p2++;
            sum++;
        }
    }
    
    int get(int L,int R,LL num,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            int left=0,right=r-l,pos=-1;
    
            while(left<=right)
            {
                int mid=(left+right)/2;
                if((LL)s[rt][mid]>num) right=mid-1;
                else left=mid+1,pos=mid;
            }
    
            return pos+1;
        }
    
        int m=(l+r)/2,x1=0,x2=0;
        if(L<=m) x1=get(L,R,num,l,m,2*rt);
        if(R>m) x2=get(L,R,num,m+1,r,2*rt+1);
        return x1+x2;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%lld",&n,&k);
            for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
    
            memset(h,-1,sizeof h);
            memset(r,sz=0,sizeof r);
            for(int i=0;i<8*maxn;i++) s[i].clear();
    
            for(int i=1;i<=n-1;i++)
            {
                int u,v; scanf("%d%d",&u,&v);
                add(u,v); r[v]++;
            }
    
            for(int i=1;i<=n;i++) if(r[i]==0) root=i;
            sz=0; dfs(root); build(1,2*n,1);
    
            LL Ans=0;
            for(int i=1;i<=n;i++)
            {
                if(L[i]+1==R[i]) continue;
                if(v[i]==0) { Ans=Ans+(R[i]-L[i]-1); continue; }
                Ans=Ans+get(L[i]+1,R[i]-1,k/v[i],1,2*n,1);
            }
            printf("%lld
    ",Ans/2);
        }
        return 0;
    }
  • 相关阅读:
    LeetCode周赛#206
    CET-6备考丨词组、佳句积累
    界面设计9.24第一次课
    图像超分辨率重建
    OpenGL和计算机图形学初步认识
    OpenGL装gult库
    安装java
    vs2019配置Opengl
    最长上升子序列(最长递增子序列)LIS
    c++科学计数法 、long long的范围
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5865149.html
Copyright © 2011-2022 走看看