zoukankan      html  css  js  c++  java
  • Count on a tree

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

    N,M<=100000

    题解

    一开始看了标签:嗯,主席树。那么一定就要放在序列上搞,dfs序。然后又是一条链,树链剖分,每次提取log个区间出来,就像树状数组套主席树一样。

    然后就re了。

    嗯,上界开小了,离散化。

    T了。

    题解:树上差分,维护点到根的主席树,维护四个根即可x,y,lca,fa[lca]。

    然后就A了。

    #include<map>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define re register
    const int maxn=100005;
    int n,m,a[maxn];
    int cnt,head[maxn];
    int fa[maxn][21],dep[maxn];
    int root[maxn],ls[maxn*50],rs[maxn*50],sum[maxn*50];
    struct edge{
        int x,y,next;
    }e[maxn<<1];
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    void write(int x){
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    
    void add(int x,int y){
        e[++cnt]=(edge){x,y,head[x]};
        head[x]=cnt;
    }
    
    void copy(int x,int y){ls[x]=ls[y];rs[x]=rs[y];sum[x]=sum[y];}
    
    int build(int rt,int l,int r,int pos){
        int t=++cnt;
        copy(t,rt);
        sum[t]++;
        if(l==r) return t;
        int mid=(l+r)>>1;
        if(pos<=mid) ls[t]=build(ls[t],l,mid,pos);
        else rs[t]=build(rs[t],mid+1,r,pos);
        return t;
    }
    
    void dfs(int x){
        root[x]=build(root[fa[x][0]],1,n,a[x]);
        for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y;
            if(y==fa[x][0]) continue;
            fa[y][0]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    }
    
    int lca(int x,int y){
        if(dep[x]>dep[y]) swap(x,y);
        int delt=dep[y]-dep[x];
        for(int i=0;delt;i++,delt>>=1)
         if(delt&1) y=fa[y][i];
        if(x==y) return x;
        for(int i=20;fa[x][0]!=fa[y][0];i--)
         if(fa[x][i]!=fa[y][i])
          x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int query(int x1,int x2,int y1,int y2,int k){
        int l=1,r=n;
        while(1){
            if(l==r) return l;
            int ret=sum[ls[x1]]+sum[ls[x2]]-sum[ls[y1]]-sum[ls[y2]],mid=(l+r)>>1;
            if(ret>=k){
                x1=ls[x1];x2=ls[x2];y1=ls[y1];y2=ls[y2];
                r=mid;
            }
            else {
                x1=rs[x1];x2=rs[x2];y1=rs[y1];y2=rs[y2];
                l=mid+1;k-=ret;
            }
        }
    }
    
    inline int query(int x,int y,int k){
        int t=lca(x,y);
        return query(root[x],root[y],root[t],root[fa[t][0]],k);
    }
    
    int tot,b[maxn],cx[maxn];
    
    int main(){
        read(n);read(m);
        for(re int i=1;i<=n;i++) read(a[i]),b[++tot]=a[i];
        sort(b+1,b+n+1);
        tot=unique(b+1,b+tot+1)-b-1;
        for(re int i=1;i<=n;++i){
            int x=lower_bound(b+1,b+tot+1,a[i])-b;
            cx[x]=a[i];
            a[i]=x;
        }
        for(re int i=1;i<n;++i){
            int x,y;
            read(x);read(y);
            add(x,y);add(y,x);
        }
        cnt=0;
        dfs(1);
        int ans=0;
        while(m--){
            int x,y,k;
            read(x);read(y);read(k);
            x^=ans;
            write(ans=cx[query(x,y,k)]);
            putchar(10);
        }
    }
    树上差分

    不过讲道理,$O(nlog^{2}n)$也至于慢那么多(第一个点就60s,还是加了各种优化)。

    然后关于静态k大

  • 相关阅读:
    会议管理要素
    项目管理—沟通管理
    项目管理的五大过程组和十大知识领域
    fastjson $ref引用问题
    项目管理——问题解决方法
    windows服务器添加磁盘后,提示The disk is offline because of policy set by an administrator的解决办法
    关于bat/cmd中转义符的使用
    关于bat中日期时间字符串的格式化
    关于windows服务器的Security安全类日志的导出
    关于windows服务器创建一个ps1脚本的周期性定时任务
  • 原文地址:https://www.cnblogs.com/sto324/p/11644488.html
Copyright © 2011-2022 走看看