• bzoj2589【 Spoj 10707】 Count on a tree II


    题目描述

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

    输入格式

    第一行两个整数N,M。
    第二行有N个整数,其中第i个整数表示点i的权值。
    后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
    最后M行每行两个整数(u,v),表示一组询问。
    数据范围是N<=40000 M<=100000 点权在int范围内 

    输出格式

    M行,表示每个询问的答案。
    • 题解

      • 树上莫队;
      • 如果不要求强制在线的话比较传统;
      • 强制在线有点麻烦:
      • 对树按深度分块,当一个点向下的深度超过$sqrt{N}$就分一块;
      • 这样分块保证了深度和块的数量在$O(sqrt{N})$内,并且每一个块都是一颗子树;
      • 预处理每个块的根对其他所有点的答案,这是$O(nsqrt{N})$的时间和空间的;
      • 考虑一个询问$u,v$如果在同一个块里则暴力查询;$O(sqrt{N})$
      • 否则假设$u$的根比$v$的根要深,否则交换;
      • 利用预处理得到$(root_{u},v)$的答案$O(1)$,暴力查询$u$到$root_{u})$的颜色$O(sqrt{N})$;
      • 只需要查询某个颜色是否出现过;
      • 可持久化块状链表记录$u$到原树的根链上的每个颜色出现的最大深度;$O(sqrt{N})$
      • 枚举的颜色没有出现过即查询颜色的最大深度一定小于$lca$的深度;
        • 可持久化块状链表:
        • 对颜色分块,记录每个历史版本每个块的起点;
        • 插入的时候暴力复制上一个版本的起点,暴力新建一个修改位置的块并更新起点
    •   1 #include<bits/stdc++.h>
        2 using namespace std;
        3 const int N=40010,M=410;
        4 int n,m,o=1,hd[N],F[N],num[N],tot,sub[N],dep[N],rt,c[N],ans;
        5 int B,sum[M][N],bl[N],cnt,len[N],Rt[M],sta[N],top;
        6 int min(int x,int y){return x<y?x:y;}
        7 int max(int x,int y){return x>y?x:y;}
        8 struct Edge{int v,nt;}E[N<<1];
        9 char gc(){
       10     static char*p1,*p2,s[1000000];
       11     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
       12     return(p1==p2)?EOF:*p1++;
       13 }
       14 int rd(){
       15     int x=0,f=1; char c=gc();
       16     while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
       17     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
       18     return x*f;
       19 }
       20 void adde(int u,int v){
       21     E[o]=(Edge){v,hd[u]};hd[u]=o++;
       22     E[o]=(Edge){u,hd[v]};hd[v]=o++;
       23 }
       24 namespace Block{
       25     int l[N][M],a[N*M],Cnt,bl[N],B,st[M],ed[M],sz;
       26     void init(){
       27         B=sqrt(tot)+1;
       28         for(int i=1;i<=tot;++i)bl[i]=(i-1)/B+1,a[i]=-1;
       29         sz=bl[tot];
       30         for(int i=1;i<=sz;++i){
       31             l[0][i]=st[i]=ed[i-1]+1;
       32             ed[i]=ed[i-1]+B;
       33         }
       34         ed[sz]=Cnt=tot;
       35     }
       36     int que(int u,int x){return a[l[u][bl[x]]+(x-1)%B];}
       37     void ins(int u,int x){
       38         for(int i=1;i<=sz;++i)l[u][i]=l[F[u]][i];
       39         int len=ed[bl[x]]-st[bl[x]],tmp=l[u][bl[x]],pre=Cnt;
       40         for(int i=0;i<=len;++i)a[++Cnt]=a[tmp+i];
       41         a[pre+1+(x-1)%B]=dep[u];
       42         l[u][bl[x]]=pre+1;
       43     }
       44 }
       45 void upd(int x,int y){
       46     if((num[x]==0)^(num[x]+y==0))tot+=y;
       47     num[x]+=y;
       48 }
       49 void dfs1(int u,int fa){
       50     upd(c[u],1);
       51     sum[cnt][u]=tot;
       52     for(int i=hd[u];i;i=E[i].nt)if(E[i].v!=fa)dfs1(E[i].v,u);
       53     upd(c[u],-1);
       54 }
       55 void dfs(int u,int fa){
       56     int x=c[u];
       57     F[u]=fa;
       58     Block::ins(u,x);
       59     sta[++top]=u;
       60     for(int i=hd[u];i;i=E[i].nt){
       61         int v=E[i].v;
       62         if(v==fa)continue;
       63         dep[v]=dep[u]+1;
       64         dfs(v,u);
       65         len[u]=max(len[v]+1,len[u]);
       66     }
       67     if(len[u]>=B||u==1){
       68         len[u]=-1;
       69         Rt[++cnt]=u;
       70         int v;do{
       71             bl[v=sta[top--]]=cnt;
       72         }while(v!=u);
       73         dfs1(u,0);
       74     }
       75 }
       76 namespace LCA{
       77     int son[N],tp[N],sz[N],F[N];
       78     void dfs1(int u,int fa){
       79         sz[u]=1;son[u]=0;F[u]=fa; 
       80         for(int i=hd[u];i;i=E[i].nt){
       81             int v=E[i].v;
       82             if(v==fa)continue;
       83             dfs1(v,u);
       84             sz[u]+=sz[v];
       85             if(sz[v]>sz[son[u]])son[u]=v;
       86         } 
       87     }
       88     void dfs2(int u,int T){
       89         tp[u]=T;
       90         if(son[u])dfs2(son[u],T);
       91         for(int i=hd[u];i;i=E[i].nt){
       92             int v=E[i].v;
       93             if(v==F[u]||v==son[u])continue;
       94             dfs2(v,v);
       95         }
       96     }
       97     int ask(int u,int v){
       98         int tu=tp[u],tv=tp[v];
       99         while(tu!=tv){
      100             if(dep[tu]<dep[tv])v=F[tv],tv=tp[v];
      101             else u=F[tu],tu=tp[u];
      102         }
      103         return dep[u]<dep[v]?u:v;
      104     }
      105     void init(){dfs1(1,0);dfs2(1,1);}
      106 }
      107 void query1(int u,int v){
      108     int x=Rt[bl[u]],y=Rt[bl[v]],dz=dep[LCA::ask(u,v)];
      109     if(dep[x]<dep[y])swap(x,y),swap(u,v);   
      110     ans=sum[bl[u]][v];
      111     for(int w=u;w!=x;w=F[w]){
      112         int d = max(Block::que(x,c[w]),Block::que(v,c[w]));
      113         if(!num[c[w]]&&d<dz)num[c[w]]=1,ans++;
      114     }
      115     for(int w=u;w!=x;w=F[w])num[c[w]]=0;
      116     printf("%d
      ",ans);
      117 }
      118 void query2(int u,int v){
      119     int dz=dep[LCA::ask(u,v)];
      120     ans=0;
      121     for(int w=u;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++;
      122     for(int w=v;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++;
      123     for(int w=u;dep[w]>=dz;w=F[w])num[c[w]]=0;
      124     for(int w=v;dep[w]>=dz;w=F[w])num[c[w]]=0;
      125     printf("%d
      ",ans);
      126 }
      127 int find(int x){
      128     int l=1,r=tot,mid;
      129     while(l<r){
      130         if(x<=sub[mid=l+r>>1])r=mid;
      131         else l=mid+1;
      132     }
      133     return l;
      134 }
      135 int main(){
      136     #ifndef ONLINE_JUDGE
      137     freopen("bzoj2589.in","r",stdin);
      138     freopen("bzoj2589.out","w",stdout);
      139     #endif
      140     n=rd();m=rd();
      141     B=sqrt(n)+1;
      142     for(int i=1,x;i<=n;++i)c[i]=sub[i]=rd();  
      143     for(int i=1,u,v;i<n;++i)adde(rd(),rd());
      144     tot=n;sort(sub+1,sub+tot+1);
      145     tot=unique(sub+1,sub+tot+1)-sub-1;
      146     for(int i=1;i<=n;++i)c[i]=lower_bound(sub+1,sub+tot+1,c[i])-sub;
      147     Block::init();
      148     dep[0]=-1;
      149     tot=0;dfs(1,0);
      150     LCA::init(); 
      151     for(int i=1,x,y;i<=m;++i){
      152         x=rd()^ans,y=rd();
      153         if(bl[x]!=bl[y])query1(x,y);
      154         else query2(x,y);
      155     }
      156     return 0;
      157 }
      bzoj2589
  • 相关阅读:
    String驻留带来的危害
    Go语言的堆栈分析
    SecureCRT使用技巧
    Javascript中相同Function使用多个名称
    记录Office Add-in开发经验
    Silverlight和WPF中DataContractJsonSerializer对时间的处理差异
    ASP.NET MVC项目实践技巧
    有点担心Node.js的未来了
    回首经典的SQL Server 2005
    duilib关于学习Demo中的QQ
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10344024.html
Copyright © 2020-2023  润新知