Wannafly挑战赛16 #E 弹球弹弹弹 splay+基环树+各种思维

 

链接:https://ac.nowcoder.com/acm/problem/16033
来源:牛客网

有n个位置,标号为1到n的整数,m次操作,第i次操作放置一个弹球在b[i] xor c[i-1]处,并询问b[i] xor c[i-1]处弹球个数c[i]
每次操作后,在x处的弹球被弹到a[x],规定c[0]=0

把球弹来弹去的位置关系刻画出来的话是一个基环树森林的结构.
每个不在环里的点会逐渐走向环,最终循环地在环里不停的转.
然后你发现如果查询不在环上的点可以用一个 $splay$ 来维护每个联通块中每一个 $dep[u]+time[u]$ 的 $dfs$ 序.
其实就是对于每一条链都以连续区间插入,这样查询的时候是区间查询.
然后对于环上的点如何查询什么时候到就自己 $yy$ 一下吧,这个我实在是想不起来了,细节多的要命.

#include<bits/stdc++.h>   
#include <unordered_map>
using namespace std;  
#define rg register
#define O2 __attribute__((optimize("-O2")))
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;}
const int maxn=500003;
const int inf=10000000;
void setIO(string s) {
    string in=s+".in";
    freopen(in.c_str(),"r",stdin);
    freopen("tt.out","w",stdout);
}
struct Splay {
    #define lson ch[x][0]
    #define rson ch[x][1]
    int cnt;
    int ch[maxn][2],siz[maxn],f[maxn],mn[maxn],mx[maxn],pos[maxn]; 
    O2 inline void init() {
        cnt=0,mx[0]=-inf,mn[0]=inf;                      
    }
    O2 inline int get(int x) {
        return ch[f[x]][1]==x;
    }
    O2 inline void pushup(int x) {     
        siz[x]=siz[lson]+siz[rson]+1;
        mx[x]=mn[x]=pos[x]; 
        mx[x]=max(mx[x],mx[rson]);
        mn[x]=min(mn[x],mn[lson]);
    }
    O2 inline void rotate(int x) {
        int old=f[x],fold=f[old],which=get(x);
        ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
        ch[x][which^1]=old,f[old]=x,f[x]=fold;
        if(fold) ch[fold][ch[fold][1]==old]=x;   
        pushup(old), pushup(x);
    }
    O2 inline void splay(int x,int &tar) {
        int u=f[tar],fa;
        for(;(fa=f[x])^u;rotate(x))
            if(f[fa]^u)
                rotate(get(fa)==get(x)?fa:x);
        tar=x;
    }
    O2 void insert(int &x,int p,int ff) {
        if(!x) {
            x=++cnt,f[x]=ff,pos[x]=p;
            pushup(x);
            return;
        }
        insert(ch[x][p>pos[x]],p,x), pushup(x);                 
    }            
    O2 int query(int x,int l,int r) {    
        if(!x||mx[x]<l||mn[x]>r) return 0;
        if(mn[x]>=l&&mx[x]<=r) return siz[x];             
        int re=0;
        if(pos[x]>=l&&pos[x]<=r) ++re;
        return re+query(lson,l,r)+query(rson,l,r);  
    }
    #undef lson
    #undef rson
}tr;  
struct Graph { 
    int edges;
    int hd[maxn],to[maxn],nex[maxn];
    O2 inline void addedge(int u,int v) {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
    }
}G,V; 
int oo[maxn];
vector<int>mm[maxn<<1];
vector<int>cir[maxn];
unordered_map<int, vector<int> >ins[maxn]; 
int n,m,id,tim;
int idx[maxn],dep[maxn],dfn[maxn],st[maxn],ed[maxn],top[maxn],dis[maxn];       
unordered_map<int,int>rt[maxn];      
unordered_map<int,int>bu[maxn];
namespace prepare {
    int du[maxn];
    queue<int>Q;
    O2 void dfs(int u) {
        cir[idx[u]].push_back(u);  
        for(rg int i=V.hd[u];i;i=V.nex[i])
        {
            int v=V.to[i];       
            if(du[v]&&!idx[v]) {
                idx[v]=idx[u];
                dfs(v);
                break;
            }
        }
    }
    O2 inline void work() {
        for(rg int i=1;i<=V.edges;++i) ++du[V.to[i]];    
        for(rg int i=1;i<=n;++i) if(!du[i]) Q.push(i);   
        while(!Q.empty()) {
            int u=Q.front(); Q.pop(); 
            for(rg int i=V.hd[u];i;i=V.nex[i]) {
                int v=V.to[i];    
                --du[v];  
                if(!du[v]) Q.push(v);
            }
        }
        for(rg int i=1;i<=n;++i) {
            if(!du[i]) continue;
            if(!idx[i]) idx[i]=++id, dfs(i);  
        }
    }
};
O2 void dfs(int u,int ff) {
    dep[u]=dep[ff]+1,st[u]=++tim,dfn[tim]=u;
    for(rg int i=G.hd[u];i;i=G.nex[i]) {
        int v=G.to[i];
        if(v==ff||idx[v]) continue;    
        top[v]=top[u],dfs(v,u);
    }
    ed[u]=tim;
}
O2 int main() {
    // setIO("input");
    n=rd(); 
    memset(oo, -1, sizeof(oo));  
    for(rg int i=1;i<=n;++i) {
        int x=rd();
        V.addedge(i,x);      // 基环树
        G.addedge(x,i);      // 建树
    }  
    prepare::work(), tr.init();
    for(rg int i=1;i<=id;++i)
        for(rg int j=0;j<cir[i].size();++j) {
            top[cir[i][j]]=cir[i][j],dep[0]=-1,dfs(cir[i][j], 0);           
            dis[cir[i][j]]=j;           
        }
    m=rd();
    int lastans=0;
    for(rg int i=0;i<m;++i) {
        int b,cur,cur_id,cur_siz;
        b=rd(), b^=lastans, lastans=0;      
        cur_id=idx[top[b]];
        cur_siz=cir[cur_id].size();  
        int x1 = (dis[top[b]] - (i%cur_siz) + cur_siz) % cur_siz;
        int x2 = dep[b]%cur_siz;       
        int tmp = (x1 - x2 + cur_siz) % cur_siz;                                
        ins[cur_id][i+dep[b]].push_back(tmp), mm[i+dep[b]].push_back(cur_id);
        for(rg int o=0;o<mm[i].size();++o) {
            int uu=mm[i][o];        
            if(oo[uu]!=i) {
                oo[uu]=i;
                for(rg int j=0;j<ins[uu][i].size();++j) bu[uu][ins[uu][i][j]]+=1;
            }
        }        
        if(idx[b]) lastans+=bu[cur_id][(dis[b]-(i%cur_siz)+cur_siz)%cur_siz]; 
        else {
            cur=dep[b]+i;         
            tr.insert(rt[cur_id][cur], st[b], 0) , tr.splay(tr.cnt, rt[cur_id][cur]);
            int a=tr.query(rt[cur_id][cur],st[b],ed[b]);
            lastans+=a;
        }
        printf("%d\n",lastans);       
    }
    return 0;
}

  

posted @ 2019-07-26 23:44  EM-LGH  阅读(217)  评论(0编辑  收藏  举报