zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    Day05_java方法 方法
    Day05_java流程控制 break、continue
    Day05_java流程控制 循环结构
    Day05_java流程控制 switch选择结构
    Day05_java流程控制结构
    Day04_java流程控制 顺序结构
    Day04_java流程控制 用户交换Scanner
    Day03_java基础 JavaDoc生成文档
    Day03_java基础 包机制
    ltib学习抄录
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9092175.html
Copyright © 2011-2022 走看看