• bzoj 4763: 雪辉


    Description

    给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex
    mex就是一个集合中最小的没有出现的非负整数,注意0要算
    比如说集合是1,9,2,6,0,8,1,7,则出现了0,1,2,6,7,8,9这7种不同的点权,因为没有3所以mex是3

    Solution

    暴力做法是枚举把点对 ((x,y)) 往上跳,用桶记录一下答案
    我们想办法把往上跳的过程分块优化,于是随机 (sqrt{n}) 个点作为关键点
    预处理出每一个关键点往上跳到的第一个关键点和到往上的每一个关键点的桶
    这样询问就可以先暴力找到第一个关键点,然后从关键点开始每次跳到下一个关键点,再从最后一个跳到 (lca),跳的次数期望是 (sqrt{n})
    这个桶用 (bitset) 代替,就可以 (O(frac{30000}{32})) 的合并的了
    由于要找 (mex) 所以要手写
    关于区间 (mex) 判断每一个数字是否是满的,如果不满,则暴力扫这个数字的每一位
    (count) 函数也可以预处理出每一个数字的 (1) 的个数
    这样 (mex,count) 的复杂度都是 (O(frac{30000}{32}))

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=1e5+10,B=320;
    int n,Q,m,T,a[N],head[N],nxt[N*2],to[N*2],num=0,p[N],dep[N];
    bool imp[N];int fa[N][18],t[N],id[N],top[N],mx=0;
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    bitset<30001>f[B+1][B+1],g,ans;//B*B*30000*4/1024/1024
    inline void dfs(int x){
    	for(int i=1;i<=17;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
    	for(int i=head[x],u;i;i=nxt[i]){
    		if(dep[u=to[i]])continue;
    		dep[u]=dep[x]+1;fa[u][0]=x;dfs(u);
    	}
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=17;i>=0;i--)if((dep[x]-dep[y])>>i&1)x=fa[x][i];
    	if(x==y)return x;
    	for(int i=17;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    inline void solve(int u){
    	int x=p[u];g.reset();
    	while(x){
    		g.set(a[x]);
    		if(imp[x]){
    			f[u][id[x]]=g;
    			if(x!=p[u] && !top[p[u]])top[p[u]]=x;
    		}
    		x=fa[x][0];
    	}
    }
    inline int getmex(){
    	for(int i=0;i<=mx;i++)if(!ans[i])return i;
    	return mx+1;
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      //cout<<(sizeof(f)+sizeof(pre))/1000/1000<<endl;
      srand(19260817);
      int x,y,k,z,lastans=0;
      cin>>n>>Q>>T;
      for(int i=1;i<=n;i++)gi(a[i]),mx=max(mx,a[i]);
      for(int i=1;i<n;i++){
    	  gi(x);gi(y);
    	  link(x,y);link(y,x);
      }
      for(int i=1;i<=n;i++)p[i]=i;
      random_shuffle(p+1,p+n+1);
      for(int i=(m=min(B,n));i>=1;i--)imp[p[i]]=1,id[p[i]]=i;
      dep[1]=1;dfs(1);
      for(int i=1;i<=m;i++)solve(i);
      while(Q--){
    	  gi(k);ans.reset();
    	  while(k--){
    		  gi(x);gi(y);x^=(lastans*T);y^=(lastans*T);
    		  z=lca(x,y);ans.set(a[z]);
    		  
    		  while(x!=z && !imp[x])ans.set(a[x]),x=fa[x][0];
    		  int last=id[x];
    		  while(imp[x] && dep[top[x]]>=dep[z])x=top[x];
    		  ans|=f[last][id[x]];
    		  while(x!=z)ans.set(a[x]),x=fa[x][0];
    
    		  while(y!=z && !imp[y])ans.set(a[y]),y=fa[y][0];
    		  last=id[y];
    		  while(imp[y] && dep[top[y]]>=dep[z])y=top[y];
    		  ans|=f[last][id[y]];
    		  while(y!=z)ans.set(a[y]),y=fa[y][0];
    	  }
    	  int t1=ans.count(),t2=getmex();lastans=t1+t2;
    	  printf("%d %d
    ",t1,t2);
      }
      return 0;
    }
    
    
  • 相关阅读:
    阶乘
    资金账号,手机号等中间添加*(星号),脱敏
    对象深拷贝
    前端简易服务器
    Codeforces Round #603 (Div. 2) C. Everyone is a Winner! (数学)
    Codeforces Round #603 (Div. 2) B. PIN Codes
    Codeforces Round #603 (Div. 2) A. Sweet Problem(数学)
    Codeforces Round #605 (Div. 3) E. Nearest Opposite Parity(最短路)
    Codeforces Round #605 (Div. 3) D. Remove One Element(DP)
    Codeforces Round #605 (Div. 3) C. Yet Another Broken Keyboard
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9092175.html
Copyright © 2020-2023  润新知