• BZOJ 2588: Spoj 10628. Count on a tree


    2588: Spoj 10628. Count on a tree

    Time Limit: 12 Sec  Memory Limit: 128 MB
    Submit: 5620  Solved: 1336
    [Submit][Status][Discuss]

    Description

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
     

    Input

    第一行两个整数N,M。
    第二行有N个整数,其中第i个整数表示点i的权值。
    后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
    最后M行每行两个整数(u,v,k),表示一组询问。
     

    Output

    M行,表示每个询问的答案。最后一个询问不输出换行符

    Sample Input

    8 5
    105 2 9 3 8 5 7 7
    1 2
    1 3
    1 4
    3 5
    3 6
    3 7
    4 8
    2 5 1
    0 5 2
    10 5 3
    11 5 4
    110 8 2

    Sample Output

    2
    8
    9
    105
    7

    HINT

    HINT:

    N,M<=100000

    暴力自重。。。

    Source

    鸣谢seter

    分析:

    树上的主席树,我们对于每一个节点维护一个当前结点到根节点的路径上的权值线段树,然后查询的时候对于x到y的路径我们用sum[x]+sum[y]-sum[lca]-sum[fa[lca]]来查询...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
      
    const int maxn=200000+5,maxm=7000000+5;
      
    int n,m,cnt,len,tot,w[maxn],hd[maxn],mp[maxn],ls[maxm],rs[maxm],to[maxn],fa[maxn][25],nxt[maxn],sum[maxm],dep[maxn],root[maxn];
      
    inline void add(int x,int y){
        to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
    }
      
    inline int find(int x){
        int l=1,r=len,ans;
        while(l<=r){
            int mid=(l+r)>>1;
            if(mp[mid]>=x)
                ans=mid,r=mid-1;
            else
                l=mid+1;
        }
        return ans;
    }
      
    inline void change(int l,int r,int x,int &y,int val){
        y=++tot,sum[y]=sum[x]+1;
        if(l==r)
            return;
        int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x];
        if(val<=mid)
            change(l,mid,ls[x],ls[y],val);
        else
            change(mid+1,r,rs[x],rs[y],val);
    }
      
    inline void dfs(int rt,int f){
        change(1,len,rt==1?root[0]:root[fa[rt][0]],root[rt],find(w[rt]));
        for(int i=hd[rt];i!=-1;i=nxt[i])
            if(to[i]!=f)
                dep[to[i]]=dep[rt]+1,fa[to[i]][0]=rt,dfs(to[i],rt);
    }
      
    inline void init(void){
        for(int j=1;j<=20;j++)
            for(int i=1;i<=n;i++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
    }
      
    inline int LCA(int x,int y){
        if(dep[x]<dep[y])
            swap(x,y);
        int d=dep[x]-dep[y];
        for(int i=0;i<=20;i++)
            if((d>>i)&1)
                x=fa[x][i];
        if(x==y)
            return x;
        for(int i=20;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
      
    inline int query(int l,int r,int x,int y,int lca,int flca,int num){
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        if(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]>=num)
            return query(l,mid,ls[x],ls[y],ls[lca],ls[flca],num);
        else
            return query(mid+1,r,rs[x],rs[y],rs[lca],rs[flca],num-(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]));
    }
      
    signed main(void){
        memset(hd,-1,sizeof(hd));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]),mp[i]=w[i];
        sort(mp+1,mp+n+1),len=unique(mp+1,mp+n+1)-mp-1;
        for(int i=1,x,y;i<n;i++)
            scanf("%d%d",&x,&y),add(x,y),add(y,x);
        fa[1][0]=1;dfs(1,-1);init();int ans=0,lca;
        for(int i=1,s,x,y;i<=m;i++){
            scanf("%d%d%d",&x,&y,&s),lca=LCA(ans^x,y),printf("%d",ans=mp[query(1,len,root[ans^x],root[y],root[lca],root[lca==1?0:fa[lca][0]],s)]);
            if(i<m)
                puts("");
        }
        return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    POWERSHELL脚本执行权限
    tcp连接状态查看
    shutdown vs close
    tcp timestamps
    与TIME_WAIT相关的几个内核参数修改测试讨论结论
    添加 vip
    tcp nonblock connection rst
    tcp keepalive选项
    grep搜索文本
    protobuf 测试使用
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6392674.html
Copyright © 2020-2023  润新知