zoukankan      html  css  js  c++  java
  • Problem: Query on the tree(二分+划分树)

    题目链接:

    Problem: Query on the tree

    Time limit: 1s     Mem limit: 64 MB     
    Problem Description

    There is a tree with n node, labeled from 1 to n, and the root of the tree is 1.

    For every node i, if its father is j, its value vi=vj*i%20161119, the value of the root is 1.

    Now monster has q queries, for each query, monster give you a node i and a number k (0<=k<20161119),

     

    you should find a node j in i’s subtree to minimize abs(k-vj).

    Input

    Multiple cases.

    In first line there is a number n (n<=1e5), then next n-1 lines, each describes an edge of

    the tree.

    Next line there is a number q(q<=1e5), then next q lines, each contains two numbers i and k.

     

     

    Output

    Each line output a single number, the minimum number of abs(vj-k).

     

     

    Sample Input
    7 1 2 1 3 2 4 2 5 3 6 3 7 5 1 4 2 7 3 30 6 0 7 7
    Sample Output
    1 1 9 18 14
     
    题意:给出一棵树和每个节点的点权,现在m个询问,每个询问是问在一个节点的子树上找到一个节点是得那个式子的值最小;
     
    思路:dfs序之后可以得到每个点的子树对应的区间,然后再在这个区间里面找到一个最接近k的节点值,可以二分第x大,然后找到k附近的那一个或者两个数求得答案;
     
    代码:
     
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn=1e5+10;
    int n,m,first[maxn],last[maxn],cnt;
    int val[maxn];
    vector<int>ve[maxn];
    int a[maxn],tree[32][maxn],sorted[maxn],num[32][maxn];
    
    template<class T> void read(T&num) {
        char CH; bool F=false;
        for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
        for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
        F && (num=-num);
    }
    int stk[70], tp;
    template<class T> inline void print(T p) {
        if(!p) { puts("0"); return; }
        while(p) stk[++ tp] = p%10, p/=10;
        while(tp) putchar(stk[tp--] + '0');
        putchar('
    ');
    }
    
    void dfs(int cur,int fa)
    {
        val[cur]=(int)((LL)val[fa]*cur%20161119);
        int len=ve[cur].size();
        a[++cnt]=(int)val[cur];
        first[cur]=cnt;
        for(int i=0;i<len;i++)
        {
            int x=ve[cur][i];
            if(x==fa)continue;
            dfs(x,cur);
        }
        last[cur]=cnt;
    }
    void build(int dep,int l,int r)
    {
        if(l>=r)return ;
        int mid=(l+r)>>1;
        int lp=l,rp=mid+1,sum=mid-l+1;
        for(int i=l;i<=r;i++)
        {
            if(tree[dep][i]<sorted[mid])sum--;
        }
        for(int i=l;i<=r;i++)
        {
            if(i!=l)num[dep][i]=num[dep][i-1];
            else num[dep][i]=0;
            if(tree[dep][i]<sorted[mid])
            {
                tree[dep+1][lp++]=tree[dep][i];
                num[dep][i]++;
            }
            else if(tree[dep][i]==sorted[mid]&&sum>0)
            {
                tree[dep+1][lp++]=tree[dep][i];
                num[dep][i]++;
                sum--;
            }
            else
            {
                tree[dep+1][rp++]=tree[dep][i];
            }
        }
        build(dep+1,l,mid),
        build(dep+1,mid+1,r);
    }
    int query(int dep,int l,int r,int ql,int qr,int k)
    {
            if(l>=r)return tree[dep][l];
            int mid=(l+r)>>1,s,ss;
            if(l!=ql)s=num[dep][ql-1],ss=num[dep][qr]-num[dep][ql-1];
            else s=0,ss=num[dep][qr];
            if(k<=ss)return query(dep+1,l,mid,l+s,l+s+ss-1,k);
            else return query(dep+1,mid+1,r,mid+1+ql-l-s,mid+1+qr-l-s-ss,k-ss);
    }
    inline int solve(int L,int R,int k)
    {
        int ans=1e9;
        int l=1,r=R-L+1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(query(0,1,cnt,L,R,mid)<=k)l=mid+1;
            else r=mid-1;
        }
        int pos=l-1;
        if(pos)
        {
            ans=min(ans,abs(k-query(0,1,cnt,L,R,pos)));
            if(pos<=R-L)ans=min(ans,abs(k-query(0,1,cnt,L,R,pos+1)));
        }
        else ans=min(ans,abs(k-query(0,1,cnt,L,R,pos+1)));
        return ans;
    }
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            int u,v;
            cnt=0;val[0]=1;
            for(int i=0;i<=n;++i)
            {
                ve[i].clear();
                for(int j=0;j<32;++j)
                    tree[j][i]=num[j][i]=0;
            }
            for(int i=1;i<n;++i)
            {
                read(u);read(v);
                ve[u].push_back(v);
                ve[v].push_back(u);
            }
            dfs(1,0);
            for(int i=1;i<=cnt;++i)sorted[i]=tree[0][i]=a[i];
            sort(sorted+1,sorted+cnt+1);
            build(0,1,cnt);
            read(m);
            while(m--)
            {
                read(u);read(v);
                int L=first[u],R=last[u];
                print(solve(L,R,v));
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    Java EE (3) -- Java EE 6 Web Services Developer Certified Expert(1z0-897)
    二、用电信号传输 TCP/IP 数据(1)
    P2384 最短路 洛谷
    T1231 最优布线 codevs
    P3371 单源最短路径【模板】 洛谷
    spfa【模板】
    P1396 营救 洛谷
    解决Android加固多进程ptrace反调试的思路整理
    Android Dex文件格式解析
    360加固保so动态脱壳
  • 原文地址:https://www.cnblogs.com/zhangchengc919/p/6588024.html
Copyright © 2011-2022 走看看