zoukankan      html  css  js  c++  java
  • [BZOJ3757]苹果树(树上莫队)

    树上莫队共有三种写法:

      1.按DFS序列分块,和普通莫队类似。常数大,不会被卡。

      2.按块状树的方式分块。常数小,会被菊花图卡到O(n)。

      3.按[BZOJ1086]王室联邦的方式分块。常数小,不会被卡。唯一的缺点是较抽象,一个块可能是不连通的。

    权衡一下当然还是写第三种做法,具体看代码。

    然后还有一个问题,手动模拟莫队移动左右端点指针的过程,会发现LCA处较难处理,它常常是跟其它点反着的。于是我们每次移指针的时候都忽略LCA,最后询问的时候加上LCA求解答案再减去LCA。再模拟会发现,所有方案都可以处理了。

    以及要注意每个询问如果左端点所在块编号比右端点所在块大则需要交换左右端点。询问的排序方式是:若两端点不在同一块则按块编号排序,否则按DFS序排序。也就是按(bel[i],dfn[i])的双关键字排序。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 using namespace std;
     7 
     8 const int N=200010;
     9 int n,m,B,u,v,tim,top,tot,a[N],stk[N],b[N],dep[N],fa[N][20];
    10 int cnt,res,rt,vis[N],ans[N],dfn[N],s[N],h[N],to[N],nxt[N];
    11 struct P{ int l,r,x,y,id; }q[N];
    12 
    13 bool cmp(const P &x,const P &y){ return b[x.l]==b[y.l] ? dfn[x.r]<dfn[y.r] : b[x.l]<b[y.l]; }
    14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    15 
    16 void dfs(int x){
    17     dfn[x]=++tim; int tmp=top;
    18     rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1];
    19     For(i,x) if ((k=to[i])!=fa[x][0]){
    20         fa[k][0]=x; dep[k]=dep[x]+1; dfs(k);
    21         if (top-tmp>=B){ ++tot; while (top!=tmp) b[stk[top--]]=tot; }
    22     }
    23     stk[++top]=x;
    24 }
    25 
    26 int lca(int x,int y){
    27     if (dep[x]<dep[y]) swap(x,y);
    28     int t=dep[x]-dep[y];
    29     for (int i=18; ~i; i--) if (t&(1<<i)) x=fa[x][i];
    30     if (x==y) return x;
    31     for (int i=18; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    32     return fa[x][0];
    33 }
    34 
    35 void upd(int x){
    36     if (vis[x]){ s[a[x]]--; if (!s[a[x]]) res--; }
    37         else { s[a[x]]++; if (s[a[x]]==1) res++; }
    38     vis[x]^=1;
    39 }
    40 
    41 void work(int x,int y){
    42     for (; x!=y; upd(x),x=fa[x][0])
    43         if (dep[x]<dep[y]) swap(x,y);
    44 }
    45 
    46 int main(){
    47     freopen("bzoj3757.in","r",stdin);
    48     freopen("bzoj3757.out","w",stdout);
    49     scanf("%d%d",&n,&m); B=sqrt(n);
    50     rep(i,1,n) scanf("%d",&a[i]);
    51     rep(i,1,n){
    52         scanf("%d%d",&u,&v);
    53         if (!u || !v) { rt=u+v; continue; }
    54         add(u,v); add(v,u);
    55     }
    56     dfs(rt);
    57     while (top) b[stk[top--]]=tot;
    58     rep(i,1,m){
    59         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].x,&q[i].y); q[i].id=i;
    60         if (b[q[i].l]>b[q[i].r]) swap(q[i].l,q[i].r);
    61     }
    62     sort(q+1,q+m+1,cmp);
    63     int L=rt,R=rt;
    64     rep(i,1,m){
    65         work(L,q[i].l); work(R,q[i].r); L=q[i].l; R=q[i].r;
    66         int f=lca(L,R); upd(f);
    67         ans[q[i].id]=res-(int)(q[i].x!=q[i].y&&s[q[i].x]&&s[q[i].y]); upd(f);
    68     }
    69     rep(i,1,m) printf("%d
    ",ans[i]);
    70     return 0;
    71 }
  • 相关阅读:
    CF 633 E. Binary Table
    BZOJ 4589 Hard Nim
    不走弯路,微信小程序的快速入门?
    如果通过cookies和localStorage取值?
    Airbub 弃用React Native
    如何在登陆注册的时候,实现密码框的小眼睛的显示与与隐藏?
    js 实用封装 点击按钮复制到剪贴板
    css渐变写法 从左到右渐变三种颜色示例;
    vue-router 使用二级路由去实现子组件的显示和隐藏
    vue 路由传参中刷新页面参数丢失 及传参的几种方式?
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10397627.html
Copyright © 2011-2022 走看看