zoukankan      html  css  js  c++  java
  • 扩展莫队小总结 (树上/带修改莫队)

    不要在意尴尬的标题

    最裸的莫队大家都会吧,我就不多说了

    那么这是一篇关于扩展莫队的小总结

    莫队的经典应用:多次询问区间内不同元素数量

    本文将以本问题为中心,坚持....

    树上莫队

    凡是能在序列上搞的问题就可以上树

    问题变成询问某条树链上不同元素数量

    把树变成序列?$dfs$序!

    先对树处理出$dfs$序,每个节点都有一个入栈时间$st$和出栈时间$ed$。

    加入现在有给出一条链的两个端点$x,y$,设他们的公共祖先是$F$,然后分情况讨论

    (1)$x=F$或$y=F$

    我们在$dfs$序里取出$[st_{F},st_{x/y}]$这一段,发现链上的元素都只出现了一次,不在链上的元素出现0次或2次!

    我们像莫队一样搞一个插入函数,并记录树上每个节点被插入次数。奇数次代表插入,欧数次代表删除

    (2)$x,y!=F$

    假设$st_{x}<st_{y}$

    我们在$dfs$序里取出$ed_{x},st_{y}$这一段,会发现除了$F$以外,链上的其他元素都被取出来了。

    还是用同样的实现方法,最后统计答案时特判$F$的贡献即可

    裸题:Count On a Tree 2

    BZOJ上这题强制在线...

    带修改莫队

    怎么让莫队资瓷修改呢?

    在最普通的莫队里,我们记录修改的左右端点l,r。

    而修改涉及到先后顺序问题,所以要增加一维t,把修改时间记录下来

    询问的排序方式为:左端点所在块作为第一关键字。右端点所在块作为第二关键字。修改时间作为第三关键字

    如何实现呢?顺便证明一下时间复杂度

    先假设块的大小是$S$,左右指针是$L,R$

    (1)当左右指针不跨块移动时,时间戳是递增的,我们按时间依次处理询问或是修改就好

    每次不跨块移动左右指针的最大时间是$O(S)$的。最多移动$O(n)$次。不跨块移动左右指针总时间复杂度是$O(Sn)$

    如果修改的位置$in[L,R]$,处理修改对答案的影响。

    整个过程最多处理$O(n)$个修改操作。跨块移动总次数最多$O((frac{n}{S})^{2})$。修改带来的总时间复杂度是$O((frac{n}{S})^{2}n)$

    (2)当左右指针跨块移动时,时间戳需要回溯到某个时刻,我们需要还原这些修改。

    跨块移动左右指针的最大时间是$O(n)$的。最多移动$O((frac{n}{S})^{2})$次。跨块移动左右指针总时间复杂度是$O((frac{n}{S})^{2}n)$

    每次回溯的次数最多是$O(n)$的。跨块移动总次数最多$O((frac{n}{S})^{2})$。回溯带来的总时间复杂度是$O((frac{n}{S})^{2}n)$

    总时间复杂度约为$O((frac{n}{S})^{2}n+Sn)$,S的最优解是$S=n^{frac{2}{3}}$

    裸题:BZOJ 2453 维护队列

    写的有点丑,见谅qwq

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define N1 10010
     6 #define M1 1000010
     7 using namespace std;
     8  
     9 template <typename _T> void read(_T &ret)
    10 {
    11     ret=0; _T fh=1; char c=getchar();
    12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    14     ret=ret*fh;
    15 }
    16  
    17 int n,Q,de;
    18 int a[N1],pie[N1],bar[M1]; 
    19  
    20 struct MO{
    21 int l,r,t,id;
    22 friend bool operator < (const MO &s1,const MO &s2)
    23 {
    24     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
    25     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
    26     if(s1.t!=s2.t) return s1.t<s2.t;
    27 }
    28 }mo[N1];
    29  
    30 struct OP{ int x,t,w,pre; }op[N1]; 
    31 int L,R,T,N,M,now,sum;
    32  
    33 void add(int i)
    34 {
    35     bar[a[i]]++;
    36     if(bar[a[i]]==1) sum++;
    37 }
    38 void del(int i)
    39 {
    40     bar[a[i]]--;
    41     if(bar[a[i]]==0) sum--;
    42 }
    43 void ret(int t)
    44 {
    45     while(op[now+1].t<=t && now<M)
    46     {
    47         now++;
    48         if(L<=op[now].x && op[now].x<=R) del(op[now].x);
    49         op[now].pre=a[op[now].x]; a[op[now].x]=op[now].w;
    50         if(L<=op[now].x && op[now].x<=R) add(op[now].x);
    51     }
    52     while(op[now].t>t && now>0)
    53     {
    54         if(L<=op[now].x && op[now].x<=R) del(op[now].x);
    55         a[op[now].x]=op[now].pre;
    56         if(L<=op[now].x && op[now].x<=R) add(op[now].x);
    57         now--;
    58     }
    59 }
    60  
    61 int ans[N1];
    62 int main()
    63 {
    64     scanf("%d%d",&n,&Q);
    65     int i,j,q,l,r,t,sq; char str[10];
    66     for(i=1;i<=n;i++) read(a[i]);
    67     for(q=1;q<=Q;q++)
    68     {
    69         scanf("%s",str);
    70         if(str[0]=='Q'){
    71             N++; read(mo[N].l); read(mo[N].r); mo[N].t=q; mo[N].id=N;
    72         }else{
    73             M++; read(op[M].x); read(op[M].w); op[M].t=q;
    74         }
    75     }
    76     sq=(int)(pow(n,0.666666667));
    77     for(i=1;i<=n;i++) pie[i]=(i-1)/sq+1;
    78     sort(mo+1,mo+N+1);
    79     for(q=1;q<=N;q++)
    80     {
    81         l=mo[q].l, r=mo[q].r; t=mo[q].t;
    82         while(R<r) R++, add(R);
    83         while(L>l) L--, add(L);
    84         while(R>r) del(R), R--;
    85         while(L<l) del(L), L++;
    86         ret(t); 
    87         ans[mo[q].id]=sum;
    88     }
    89     for(q=1;q<=N;q++) printf("%d
    ",ans[q]); 
    90     return 0;
    91 }
    View Code

    带修改树上莫队

    把上面两个算法结合一下就行啦

    裸题:

    BZOJ 4129 Haruna’s Breakfast

    由于只有$n$个节点,所以可能对答案的产生贡献的范围只有$[0,n]$..

    套个分块,记录每个块里有多少个元素出现过。

    这样就是$O(1)$修改,$O(sqrt{n})$查询啦

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 50005
      6 using namespace std;
      7  
      8 template <typename _T> void read(_T &ret)
      9 {
     10     ret=0; _T fh=1; char c=getchar();
     11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     13     ret=ret*fh;
     14 }
     15 struct Edge{
     16 int to[N1*2],nxt[N1*2],head[N1],cte;
     17 void ae(int u,int v)
     18 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
     19 }e;
     20  
     21 int n,Q,de;
     22 int a[N1],st[N1],ed[N1],ord[N1*2],cur;
     23  
     24 namespace Tree{
     25  
     26 int fa[N1],dep[N1],sz[N1],son[N1],tp[N1];
     27 void dfs1(int x)
     28 {
     29     int j,v; sz[x]=1;
     30     for(j=e.head[x];j;j=e.nxt[j])
     31     {
     32         v=e.to[j]; if(v==fa[x]) continue;
     33         dep[v]=dep[x]+1; fa[v]=x; dfs1(v); 
     34         sz[x]+=sz[v]; son[x]=(sz[v]>sz[son[x]])?v:son[x];
     35     }
     36 }
     37 void dfs2(int x)
     38 {
     39     st[x]=++cur; ord[cur]=x;
     40     if(son[x]) tp[son[x]]=tp[x], dfs2(son[x]);
     41     int j,v;
     42     for(j=e.head[x];j;j=e.nxt[j])
     43     {
     44         v=e.to[j]; if(v==fa[x] || v==son[x]) continue;
     45         tp[v]=v; dfs2(v);
     46     }
     47     ed[x]=++cur; ord[cur]=x;
     48 }
     49 void init(){ dep[1]=1; dfs1(1); tp[1]=1; dfs2(1); }
     50 int LCA(int x,int y)
     51 {
     52     while(tp[x]!=tp[y])
     53     {
     54         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
     55         x=fa[tp[x]];
     56     }
     57     return dep[x]<dep[y]?x:y;
     58 }
     59  
     60 };
     61 using Tree::LCA; 
     62  
     63  
     64 namespace Captain_MO{
     65  
     66 int pie[N1*2],cnt[N1],vis[N1*2],num[N1],sum[N1],sq,now; 
     67  
     68 struct MO{
     69 int l,r,t,id,F;
     70 friend bool operator < (const MO &s1,const MO &s2)
     71 {
     72     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
     73     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
     74     if(s1.t!=s2.t) return s1.t<s2.t;
     75 }
     76 }mo[N1];
     77 struct OP{ int x,t,w,pre; }op[N1]; 
     78  
     79 void add(int i)
     80 {
     81     if(a[ord[i]]>n) return;
     82     if(cnt[ord[i]]&1){
     83         num[a[ord[i]]]--; 
     84         if(num[a[ord[i]]]==0) sum[a[ord[i]]/sq]--;
     85     }else{
     86         num[a[ord[i]]]++; 
     87         if(num[a[ord[i]]]==1) sum[a[ord[i]]/sq]++;
     88     }
     89     cnt[ord[i]]++;
     90 }
     91 int qmex()
     92 {
     93     int i,j;
     94     for(i=0;(i+1)*sq-1<=n;i++)
     95     {
     96         if(sum[i]==sq) continue;
     97         for(j=i*sq;j<(i+1)*sq;j++)
     98             if(!num[j]) return j;
     99     }
    100     for(j=i*sq;j<=n;j++)
    101         if(!num[j]) return j;
    102 }
    103  
    104 int L,R,N,M;
    105 void ret(int t)
    106 {
    107     int x;
    108     while(op[now+1].t<=t && now<M)
    109     {
    110         now++; x=op[now].x;
    111         if(L<=st[x] && st[x]<=R) add(st[x]);
    112         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    113         op[now].pre=a[x]; a[x]=op[now].w;
    114         if(L<=st[x] && st[x]<=R) add(st[x]);
    115         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    116     }
    117     while(op[now].t>t && now>0)
    118     {
    119         x=op[now].x;
    120         if(L<=st[x] && st[x]<=R) add(st[x]);
    121         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    122         a[x]=op[now].pre;
    123         if(L<=st[x] && st[x]<=R) add(st[x]);
    124         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    125         now--;
    126     }
    127 }
    128  
    129 int ans[N1];
    130 void Main()
    131 {
    132     int i,j,x,y,q,fl,F,l,r,t;
    133     for(j=1;j<=Q;j++)
    134     {
    135         read(fl); read(x); read(y);
    136         if(fl){
    137             N++; F=LCA(x,y); 
    138             if(x==F){
    139                 mo[N].l=st[x]; mo[N].r=st[y]; 
    140             }else if(y==F){
    141                 mo[N].l=st[y]; mo[N].r=st[x]; 
    142             }else{
    143                 if(st[x]>st[y]) swap(x,y);
    144                 mo[N].l=ed[x]; mo[N].r=st[y]; mo[N].F=F;
    145             }
    146             mo[N].t=j; mo[N].id=N;
    147         }else{ 
    148             M++; op[M].x=x; op[M].w=y; op[M].t=j; 
    149         }
    150     }
    151     sq=(int)(sqrt(cur));
    152     t=(int)(pow(cur,0.6666666667)); 
    153     for(i=1;i<=cur;i++) pie[i]=(i-1)/t+1;
    154     sort(mo+1,mo+N+1);
    155     L=1, R=1; add(1);
    156     for(q=1;q<=N;q++)
    157     {
    158         l=mo[q].l; r=mo[q].r; t=mo[q].t;
    159         while(R<r) R++, add(R);
    160         while(L>l) L--, add(L);
    161         while(R>r) add(R), R--; // del(R), R--; 
    162         while(L<l) add(L), L++; // del(L), L++; 
    163         ret(t);
    164         if(mo[q].F) add(st[mo[q].F]);
    165         ans[mo[q].id]=qmex();
    166         if(mo[q].F) add(st[mo[q].F]);
    167     }
    168     for(q=1;q<=N;q++) printf("%d
    ",ans[q]);
    169 }
    170  
    171 };
    172  
    173 int main()
    174 {
    175     scanf("%d%d",&n,&Q);
    176     int i,j,x,y; char str[10];
    177     for(i=1;i<=n;i++) read(a[i]);
    178     for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
    179     Tree::init();
    180     Captain_MO::Main();
    181     return 0;
    182 }
    View Code

    [WC2013]糖果公园

    没什么好说的..记得开long long 

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 100010
      6 #define il inline 
      7 #define ll long long
      8 using namespace std;
      9  
     10 template <typename _T> void read(_T &ret)
     11 {
     12     ret=0; _T fh=1; char c=getchar();
     13     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     14     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     15     ret=ret*fh;
     16 }
     17  
     18 struct Edge{
     19 int to[N1*2],nxt[N1*2],head[N1],cte;
     20 void ae(int u,int v)
     21 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
     22 }e;
     23  
     24 int n,m,Q;
     25 int V[N1],W[N1],a[N1];
     26 int st[N1],ed[N1],ord[N1*2],cur;
     27  
     28  
     29 namespace Tree{
     30  
     31 int fa[N1],dep[N1],tp[N1],sz[N1],son[N1];
     32 void dfs1(int x)
     33 {
     34     int j,v; sz[x]=1;
     35     for(j=e.head[x];j;j=e.nxt[j])
     36     {
     37         v=e.to[j]; if(v==fa[x]) continue;
     38         dep[v]=dep[x]+1; fa[v]=x; dfs1(v);
     39         sz[x]+=sz[v]; son[x]=(sz[v]>sz[son[x]])?v:son[x];
     40     }
     41 }
     42 void dfs2(int x)
     43 {
     44     st[x]=++cur; ord[cur]=x;
     45     if(son[x]) tp[son[x]]=tp[x], dfs2(son[x]);
     46     int j,v;
     47     for(j=e.head[x];j;j=e.nxt[j])
     48     {
     49         v=e.to[j]; if(v==son[x] || v==fa[x]) continue;
     50         tp[v]=v; dfs2(v);
     51     }
     52     ed[x]=++cur; ord[cur]=x;
     53 }
     54 void init(){ dep[1]=1; dfs1(1); tp[1]=1; dfs2(1); }
     55 int LCA(int x,int y)
     56 {
     57     while(tp[x]!=tp[y])
     58     {
     59         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
     60         x=fa[tp[x]];
     61     }
     62     return dep[x]<dep[y]?x:y;
     63 }
     64  
     65 };
     66 using Tree::LCA;
     67  
     68  
     69 namespace Captain_Mo{
     70  
     71 int L,R,N,M,now;
     72 int pie[N1*2];
     73 struct MO{
     74 int l,r,t,id,F;
     75 friend bool operator < (const MO &s1,const MO &s2)
     76 {
     77     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
     78     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
     79     return s1.t<s2.t; 
     80 }
     81 }mo[N1];
     82 struct OP{ int x,w,t,pre; }op[N1];
     83  
     84 int cnt[N1],num[N1]; ll sum;
     85 il void add(int i) 
     86 {
     87     int x=ord[i];
     88     if(cnt[x]&1){
     89         sum-=1ll*V[a[x]]*W[num[a[x]]];
     90         num[a[x]]--;
     91     }else{
     92         num[a[x]]++;
     93         sum+=1ll*V[a[x]]*W[num[a[x]]];
     94     }
     95     cnt[x]++;
     96 }
     97 void ret(int t)
     98 {
     99     int x;
    100     while(op[now+1].t<=t && now<M)
    101     {
    102         now++; x=op[now].x;
    103         if(L<=st[x] && st[x]<=R) add(st[x]);
    104         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    105         op[now].pre=a[x]; a[x]=op[now].w;
    106         if(L<=st[x] && st[x]<=R) add(st[x]);
    107         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    108     }
    109     while(op[now].t>t && now>0)
    110     {
    111         x=op[now].x;
    112         if(L<=st[x] && st[x]<=R) add(st[x]);
    113         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    114         a[x]=op[now].pre;
    115         if(L<=st[x] && st[x]<=R) add(st[x]);
    116         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
    117         now--;
    118     }
    119 }
    120  
    121 ll ans[N1];
    122 void Main()
    123 {
    124     int i,j,q,fl,x,y,F,l,r,t;
    125     for(j=1;j<=Q;j++)
    126     {
    127         read(fl); read(x); read(y);
    128         if(fl){
    129             N++; F=LCA(x,y);
    130             if(x==F){
    131                 mo[N].l=st[x]; mo[N].r=st[y]; 
    132             }else if(y==F){
    133                 mo[N].l=st[y]; mo[N].r=st[x]; 
    134             }else{
    135                 if(st[x]>st[y]) swap(x,y);
    136                 mo[N].l=ed[x]; mo[N].r=st[y]; mo[N].F=F;
    137             }
    138             mo[N].t=j; mo[N].id=N;
    139         }else{
    140             M++; op[M].x=x; op[M].w=y; op[M].t=j;  
    141         }
    142     }
    143     t=(int)(pow(cur,0.666666667));
    144     for(i=1;i<=cur;i++) pie[i]=(i-1)/t+1;
    145     sort(mo+1,mo+N+1);
    146     L=1, R=1; add(1);
    147     for(q=1;q<=N;q++)
    148     {
    149         l=mo[q].l; r=mo[q].r; t=mo[q].t;
    150         while(R<r) R++, add(R);
    151         while(L>l) L--, add(L);
    152         while(R>r) add(R), R--;
    153         while(L<l) add(L), L++;
    154         ret(t);
    155         if(mo[q].F) add(st[mo[q].F]);
    156         ans[mo[q].id]=sum;
    157         if(mo[q].F) add(st[mo[q].F]);
    158     }
    159     for(q=1;q<=N;q++) printf("%lld
    ",ans[q]);
    160 }
    161  
    162 };
    163  
    164 int main()
    165 {
    166     int i,j,x,y;
    167     scanf("%d%d%d",&n,&m,&Q);
    168     for(i=1;i<=m;i++) read(V[i]); 
    169     for(i=1;i<=n;i++) read(W[i]); 
    170     for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
    171     for(i=1;i<=n;i++) read(a[i]);
    172     Tree::init();
    173     Captain_Mo::Main();
    174     return 0;
    175 }
    176 
    View Code
  • 相关阅读:
    Codeforces Beta Round #69 (Div. 2 Only)
    Codeforces Beta Round #67 (Div. 2)
    Codeforces Beta Round #65 (Div. 2)
    UmBasketella
    Codeforces Beta Round #63 (Div. 2)
    [agc004d]Teleporter
    [arc076f]Exhausted?
    NOIp模拟赛二十八
    CDQ分治笔记
    (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10568817.html
Copyright © 2011-2022 走看看