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

    题意:给定一棵树,有点权,不带修改,询问路径点权第K大,强制在线。

    这道题建主席树的方法好机智。按照BFS/DFS序建树,对于每个点,建出“这个点到根节点的路径上的点”组成的权值线段树,某个节点的树由父节点的树更改一条链得来。查询时用路径两个端点到根的线段树减去lca到根节点的线段树的2倍就得到了这条路径。注意lca的点权要特殊处理一下,不要把lca多减一次。据说只要分别减去lca和lca的父亲即可,查询的时候传4棵线段树的节点。

    于是抖机灵强行传3个节点,单独处理lca,结果RE了一坨…..因为lca的权值小于区间中点的权值并不一定是lca处在[l,r]区间的左半部分,还有可能是lca在[l,r]区间的左边,加句rk[lca]>=l就过了.调了一小时,虚死….

    #include<cstdio>
    
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=100005;
    
    int n,m;
    
    struct edge{
    
        int to,next;
    
    }lst[maxn<<1];int len=1;
    
    int first[maxn];
    
    void addedge(int a,int b){
    
        lst[len].to=b;
    
        lst[len].next=first[a];
    
        first[a]=len++;
    
    }
    
    int c[maxn];
    
    int q[maxn];
    
    int depth[maxn],p[maxn][18];
    
    void bfs(){
    
        int head=0,tail=0;
    
        depth[1]=1;
    
        q[tail++]=1;
    
        int x;
    
        while(head!=tail){
    
            x=q[head++];
    
            for(int pt=first[x];pt;pt=lst[pt].next){
    
                if(lst[pt].to==p[x][0])continue;
    
                p[lst[pt].to][0]=x;
    
                depth[lst[pt].to]=depth[x]+1;
    
                q[tail++]=lst[pt].to;
    
            }
    
            for(int j=0;p[x][j];++j)p[x][j+1]=p[p[x][j]][j];
    
        }
    
    }
    
    int LCA(int u,int v){
    
        if(depth[u]<depth[v])swap(u,v);
    
        for(int j=17;j>=0;--j){
    
            if(depth[p[u][j]]>=depth[v])u=p[u][j];
    
        }
    
        if(u==v)return u;
    
        for(int j=17;j>=0;--j){
    
            if(p[u][j]!=p[v][j]){
    
                u=p[u][j];v=p[v][j];
    
            }
    
        }
    
        return p[u][0];
    
    }
    
    struct node{
    
        int sum;
    
        node *lch,*rch;
    
        node(){
    
            lch=rch=0;
    
            sum=0;
    
        }
    
    }t[maxn*50];int cnt=0;
    
    int tot=0;
    
    node *root[maxn];
    
    int qx;
    
     
    
    int seq[maxn],dict[maxn],rk[maxn];
    
    void Insert(node *rt1,node* &rt2,int l,int r){
    
        ++cnt;rt2=t+cnt;
    
        if(l==r){
    
            rt2->sum=rt1->sum+1;
    
            rt2->lch=rt2->rch=t+0;
    
            return;
    
        }
    
        int mid=(l+r)>>1;
    
        if(qx<=mid){
    
            rt2->rch=rt1->rch;
    
            Insert(rt1->lch,rt2->lch,l,mid);
    
        }else{
    
            rt2->lch=rt1->lch;
    
            Insert(rt1->rch,rt2->rch,mid+1,r);
    
        }
    
        rt2->sum=rt2->lch->sum+rt2->rch->sum;
    
    }
    
    void build_all(){
    
        root[0]=t+0;
    
        root[0]->rch=root[0]->lch=t+0;
    
        root[0]->sum=0;
    
        for(int i=0;i<n;++i){
    
            qx=rk[q[i]];
    
            Insert(root[p[q[i]][0]],root[q[i]],1,tot);
    
        }
    
    }
    
    bool cmp(const int &x,const int &y){
    
        return c[x]<c[y];
    
    }
    
    int lca;
    
    int query(node *rt1,node *rt2,node *rt3,int l,int r){
    
        if(l==r)return l;
    
        int mid=(l+r)>>1;
    
        int lsum=rt1->lch->sum+rt2->lch->sum-2*(rt3->lch->sum);
    
        if(l<=rk[lca]&&rk[lca]<=mid)lsum++;
    
        //if(rk[lca]<=mid) 错误的写法.这时rk[lca]可以小于l
    
        if(qx<=lsum)return query(rt1->lch,rt2->lch,rt3->lch,l,mid);
    
        else{
    
            qx-=lsum;
    
            return query(rt1->rch,rt2->rch,rt3->rch,mid+1,r);
    
        }
    
    }
    
    int main(){
    
        scanf("%d%d",&n,&m);
    
        for(int i=1;i<=n;++i){
    
            scanf("%d",c+i);
    
            seq[i]=i;
    
        }
    
        sort(seq+1,seq+n+1,cmp);
    
        int old=c[seq[1]]-1;
    
        for(int i=1;i<=n;++i){
    
            if(old!=c[seq[i]]){
    
                old=c[seq[i]];++tot;
    
                dict[tot]=c[seq[i]];
    
            }
    
            rk[seq[i]]=tot;
    
        }
    
        int a,b,k;
    
        for(int i=1;i<n;++i){
    
            scanf("%d%d",&a,&b);
    
            addedge(a,b);addedge(b,a);
    
        }
    
        bfs();
    
        build_all();
    
        int lastans=0;
    
        while(m--){
    
            scanf("%d%d%d",&a,&b,&k);
    
            a^=lastans;
    
            qx=k;lca=LCA(a,b);
    
            lastans=dict[query(root[a],root[b],root[lca],1,tot)];
    
            if(m)printf("%d
    ",lastans);
    
            else printf("%d",lastans);
    
        }
    
        return 0;
    
    }
  • 相关阅读:
    [题解]小X的液体混合
    [题解]图的遍历
    [模板]基本线段树操作
    C#中 Excel列字母与数字的相互转换
    Oracle 查询数据库表大小
    vi/vim 编辑、搜索、查找、定位
    Linux 中 sqlite3 基本操作
    MessageBox.Show 消息提示框显示到窗口最顶层
    Docker bash: ping: command not found 解决方法
    PLSQL F8执行单条SQL
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6008540.html
Copyright © 2011-2022 走看看