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
  • 相关阅读:
    hive与hbase整合
    待重写
    hive DML
    【知识强化】第六章 总线 6.1 总线概述
    【知识强化】第五章 中央处理器 5.1 CPU的功能和基本结构
    【知识强化】第四章 指令系统 4.3 CISC和RISC的基本概念
    【知识强化】第四章 指令系统 4.2 指令寻址方式
    【知识强化】第四章 指令系统 4.1 指令格式
    【知识强化】第三章 存储系统 3.6 高速缓冲存储器
    【知识强化】第三章 存储系统 3.5 双口RAM和多模块存储器
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10568817.html
Copyright © 2011-2022 走看看