zoukankan      html  css  js  c++  java
  • BZOJ 4771 主席树+倍增+set

    思路:

    因为有深度的限制,并且我们是在线段树上维护权值,所以我们把点按照dep排序,然后一个一个修改...主席树的下标就是dfs序,子树的查询就是区间查询...

    但是发现这样怎么去维护LCA呢...因为要求有序,所以我们可以用set来维护相同颜色的节点...如果把一个点加入集合之后这个点前驱为x,后继为y,那么我们去修正,把xy的LCA+1,然后x和当前点的LCA-1,当前点和y的LCA-1...

    from neighthorn

    //By SiriusRen
    #include <set> 
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=100050;
    int n,m,cases,v[N],next[N],first[N],tot,fa[N][20],dfn[N],cnt,root[N],lst[N],dep[N];
    int tree[N*50],lson[N*50],rson[N*50],xx,yy,ans;
    struct Node{int x,deep,col;}node[N];
    bool cmp(Node a,Node b){return a.deep<b.deep;}
    bool cmp2(Node a,Node b){return a.x<b.x;}
    struct Cmp{bool operator()(Node a,Node b){return dfn[a.x]<dfn[b.x];}};
    set<Node,Cmp>s[N];set<Node,Cmp>::iterator it,it2,it3;
    void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    void dfs(int x){
        dfn[x]=++cnt;
        for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x][0])
            dep[v[i]]=node[v[i]].deep=node[x].deep+1,dfs(v[i]);
        lst[x]=cnt;
    }
    void insert(int l,int r,int &pos,int last,int num,int wei){
        pos=++cnt,tree[pos]=tree[last]+wei;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(mid<num)lson[pos]=lson[last],insert(mid+1,r,rson[pos],rson[last],num,wei);
        else rson[pos]=rson[last],insert(l,mid,lson[pos],lson[last],num,wei);
    }
    int query(int l,int r,int pos,int L,int R){
        if(l>=L&&r<=R)return tree[pos];
        int mid=(l+r)>>1;
        if(mid<L)return query(mid+1,r,rson[pos],L,R);
        else if(mid>=R)return query(l,mid,lson[pos],L,R);
        else return query(l,mid,lson[pos],L,R)+query(mid+1,r,rson[pos],L,R);
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        for(int i=19;~i;i--)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i];
        if(x==y)return x;
        for(int i=19;~i;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    int main(){
        scanf("%d",&cases);
        while(cases--){
            memset(first,-1,sizeof(first)),ans=tot=cnt=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)scanf("%d",&node[i].col),node[i].x=i;
            for(int i=2;i<=n;i++)scanf("%d",&fa[i][0]),add(fa[i][0],i);
            for(int j=1;j<=19;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
            dep[1]=node[1].deep=1,dfs(1),cnt=0,sort(node+1,node+1+n,cmp);
            for(int i=1;i<=n;i++){
                int lst=node[i-1].deep,now=node[i].deep;
                insert(1,n,root[now],root[lst],dfn[node[i].x],1);
                s[node[i].col].insert(node[i]),it=s[node[i].col].find(node[i]);it2=it,++it2;
                if(s[node[i].col].size()>2&&it!=s[node[i].col].begin()&&it2!=s[node[i].col].end())
                    it2=it,it2--,it3=it,it3++,insert(1,n,root[now],root[now],dfn[lca((*it2).x,(*it3).x)],1);
                if(it!=s[node[i].col].begin())it2=it,it2--,insert(1,n,root[now],root[now],dfn[lca((*it2).x,(*it).x)],-1);
                it2=it,++it2;
                if(it2!=s[node[i].col].end())insert(1,n,root[now],root[now],dfn[lca((*it2).x,(*it).x)],-1);
            }
            while(m--){
                scanf("%d%d",&xx,&yy),xx^=ans,yy^=ans;
                printf("%d
    ",ans=query(1,n,root[min(dep[xx]+yy,node[n].deep)],dfn[xx],lst[xx]));
            }
            for(int i=1;i<=n;i++)s[i].clear(),root[i]=0;
        }
    }
    
  • 相关阅读:
    IDEA中给main方法的args传参
    spark (Java API) 在Intellij IDEA中开发并运行
    Spark在Windows下的环境搭建
    Android Studio开发第三篇版本管理Git
    Android Studio开发第二篇创建新项目
    Android Studio开发第一篇QuickStart
    AndroidのInputFillter之按字符过滤长度,一个中文当两个字符
    DownloadProvider源码解析——与Volley对比
    EGit系列第三篇——远程提交代码
    WP8.1学习系列(第二十七章)——ListView和GridView入门
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6592639.html
Copyright © 2011-2022 走看看