zoukankan      html  css  js  c++  java
  • [模板] 莫队/树上莫队/带修莫队

    莫队

    如果知道[l,r]的答案时能快速求出[l+1,r][l,r+1][l-1,r][l,r-1]的答案,那么可以用莫队离线求解

    如果要从[l,r]得到[l',r'],那么需要$O(|r'-r|+|l'-l|)$次更新答案

    所以需要确定一个求答案的顺序使得这玩意最优

    以$frac{n}{q}$分块,按l所在块为第一关键字,r为第二关键字排序

    总复杂度是$O(n sqrt q)$

    luogu1494 小Z的袜子

    询问$sum{cnt[i]*(cnt[i]-1)}$,其中cnt[i]是每种颜色出现的次数

    可以发现当$cnt[i]+=d$时,这玩意会$+=d^2+2*cnt[i]*d-d$

    于是记每种颜色出现的次数就好了

     1 #include<bits/stdc++.h>
     2 #define CLR(a,x) memset(a,x,sizeof(a))
     3 using namespace std;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 typedef pair<int,int> pa;
     7 const int maxn=5e4+10;
     8 
     9 inline ll rd(){
    10     ll x=0;char c=getchar();int neg=1;
    11     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    13     return x*neg;
    14 }
    15 
    16 int N,M,col[maxn],cnt[maxn],sqn;
    17 ll ans[maxn],len[maxn];
    18 struct Node{
    19     int l,r,i;
    20 }q[maxn];
    21 
    22 inline bool cmp(Node a,Node b){
    23     return a.l/sqn==b.l/sqn?a.r<b.r:a.l<b.l;
    24 }
    25 
    26 inline ll gcd(ll x,ll y){
    27     if(!x) return y;
    28     return gcd(y%x,x);
    29 }
    30 
    31 int main(){
    32     //freopen("","r",stdin);
    33     int i,j,k;
    34     N=rd(),M=rd();sqn=sqrt(N);
    35     for(i=1;i<=N;i++) col[i]=rd();
    36     for(i=1;i<=M;i++){
    37         q[i].l=rd(),q[i].r=rd(),q[i].i=i;
    38         len[i]=1ll*(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
    39     }
    40     sort(q+1,q+M+1,cmp);
    41     int l=1,r=0;
    42     ll tmp=0;
    43     for(i=1;i<=M;i++){
    44         if(q[i].l==q[i].r) len[q[i].i]=1;
    45         while(r<q[i].r){
    46             tmp+=cnt[col[++r]]*2;
    47             cnt[col[r]]++;
    48         }
    49         while(r>q[i].r){
    50             tmp+=2-cnt[col[r]]*2;
    51             cnt[col[r--]]--;
    52         }
    53         while(l>q[i].l){
    54             tmp+=cnt[col[--l]]*2;
    55             cnt[col[l]]++;
    56         }
    57         while(l<q[i].l){
    58             tmp+=2-cnt[col[l]]*2;
    59             cnt[col[l++]]--;
    60         }
    61         ans[q[i].i]=tmp/gcd(tmp,len[q[i].i]),len[q[i].i]/=gcd(tmp,len[q[i].i]);
    62     }
    63     for(i=1;i<=M;i++){
    64         
    65         printf("%lld/%lld
    ",ans[i],len[i]);
    66     }
    67     return 0;
    68 }
    View Code
    luogu3709 大爷的字符串题

    描述比较迷,但是分析以后给一个构造就是每次那个区间最少能给他排成几个严格递增的序列,不难发现就是众数的个数

    于是莫队,记$cnt[i]$是$i$出现的次数,$num[j]$是$cnt$为$j$出现的次数,以及目前的最大$cnt$,我这个最大的$cnt$的数量被减没了,就换到原来的最大的$-1$

     1 #include<bits/stdc++.h>
     2 #define CLR(a,x) memset(a,x,sizeof(a))
     3 #define MP make_pair
     4 using namespace std;
     5 typedef long long ll;
     6 typedef unsigned long long ull;
     7 typedef pair<int,int> pa;
     8 const int maxn=2e5+10;
     9 
    10 inline ll rd(){
    11     ll x=0;char c=getchar();int neg=1;
    12     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    13     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    14     return x*neg;
    15 }
    16 
    17 int N,NN,M,a[maxn],tmp[maxn];
    18 int ans[maxn],cnt[maxn],num[maxn];
    19 struct Node{
    20     int l,r,i;
    21 }q[maxn];
    22 
    23 inline bool cmp(Node x,Node y){
    24     return x.l/NN==y.l/NN?x.r<y.r:x.l<y.l;
    25 }
    26 
    27 int main(){
    28     //freopen("","r",stdin);
    29     int i,j,k;
    30     N=rd(),M=rd();NN=sqrt(N);
    31     for(i=1;i<=N;i++){
    32         a[i]=tmp[i]=rd();
    33     }sort(tmp+1,tmp+N+1);
    34     j=unique(tmp+1,tmp+N+1)-tmp;
    35     for(i=1;i<=N;i++)
    36         a[i]=lower_bound(tmp+1,tmp+j,a[i])-tmp;
    37     for(i=1;i<=M;i++){
    38         q[i].l=rd(),q[i].r=rd(),q[i].i=i;
    39         ans[i]=0;
    40     }
    41     sort(q+1,q+M+1,cmp);
    42     
    43     int ma=0,l=1,r=0;
    44     for(i=1;i<=M;i++){
    45         while(r<q[i].r){
    46             cnt[a[++r]]++;
    47             num[cnt[a[r]]]++,num[cnt[a[r]]-1]--;
    48             if(cnt[a[r]]>ma) ma=cnt[a[r]];
    49         }while(r>q[i].r){
    50             cnt[a[r]]--;
    51             num[cnt[a[r]]]++,num[cnt[a[r]]+1]--;
    52             if(!num[ma]) ma--;
    53             r--;
    54         }
    55         while(l>q[i].l){
    56             cnt[a[--l]]++;
    57             num[cnt[a[l]]]++,num[cnt[a[l]]-1]--;
    58             if(cnt[a[l]]>ma) ma=cnt[a[l]];
    59         }while(l<q[i].l){
    60             cnt[a[l]]--;
    61             num[cnt[a[l]]]++,num[cnt[a[l]]+1]--;
    62             if(!num[ma]) ma--;
    63             l++;
    64         }
    65         ans[q[i].i]-=ma;
    66     }
    67     for(i=1;i<=M;i++)
    68         printf("%d
    ",ans[i]);
    69     return 0;
    70 }
    View Code

    树上莫队

    针对树上路径的询问

    欧拉序做法

    考虑一棵树的欧拉序(即括号序,进和出时各记一次),如果对于一个区间,某个元素出现了两次,则认为它没出现过,那么对于路径(a,b)有两种情况(不妨设a在b前面):

    1.$a$或$b$中有一个是$lca$:$[in[a],in[b]]$

    2.否则:$[out[a],in[b]]U{lca}$

    画图理解即可

    于是就变成了和普通莫队一样。但需要注意的是这个区间不能拆,所以有一些题做不了...

    树分块做法

    考虑按某种方法对树分块,最后排序时的关键字改为那个点所属的块的编号

    考虑dfs时维护一个栈,进入点x时记下栈中元素个数,每从一个x的子树出来时,判断一下新增的元素个数是否大于$B$(块大小),如果大于的话,把新增的这些点分到同一个块里;出x的时候将x计入栈中。最后剩下的元素扔到最后一个块里

    这样可以保证块大小都是$[B,3B]$的

     1 void dfs(int x){
     2     int t=sh;
     3     for(int i=egh[x];i;i=eg[i][1]){
     4         int b=eg[i][0];if(b==fa[x][0]) continue;
     5         fa[b][0]=x,dep[b]=dep[x]+1;dfs(b);
     6         if(sh-t>=blk){
     7             ++bct;
     8             for(;sh>t;sh--) bel[stk[sh]]=bct;
     9         }
    10     }
    11     stk[++sh]=x;
    12 }

    然后处理询问的时候,要从(a,b)到(c,b),只要考虑(a,c)路径上的点即可

    带修莫队

    可以将修改视为第三维来做,复杂度$Oleft(frac{qn^2}{B^2}+qB+frac{n^2}{B} ight)$,B是块大小

    $n=q$时可以取$B=n^{frac{2}{3}}$,复杂度是$O(n^{frac{5}{3}})$

    [WC2013]糖果公园

    带修树上莫队

      1 #include<bits/stdc++.h>
      2 #include<tr1/unordered_map>
      3 #define CLR(a,x) memset(a,x,sizeof(a))
      4 #define MP make_pair
      5 #define fi first
      6 #define se second
      7 #define oct hakheaw
      8 using namespace std;
      9 typedef long long ll;
     10 typedef unsigned long long ull;
     11 typedef long double ld;
     12 typedef pair<int,int> pa;
     13 const int maxn=1e5+10,Blk=2154;
     14 
     15 inline ll rd(){
     16     ll x=0;char c=getchar();int neg=1;
     17     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     18     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     19     return x*neg;
     20 }
     21 
     22 struct Node{
     23     int l,r,x,t,i;
     24     Node(int _l=0,int _r=0,int _x=0,int _t=0,int _i=0){l=_l,r=_r,x=_x,t=_t,i=_i;}
     25 }qr[maxn];
     26 int N,M,Q,val[maxn],eg[maxn*2][2],egh[maxn],ect,col[maxn],lik[maxn];
     27 int dfn[maxn][2],tot,id[maxn*2],fa[maxn][20],dep[maxn];
     28 int cg[maxn][3],oct,qct;
     29 int cnt[maxn];
     30 ll ans[maxn];
     31 bool flag[maxn];
     32 inline void adeg(int a,int b){
     33     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
     34 }
     35 
     36 void dfs(int x){
     37     dfn[x][0]=++tot;id[tot]=x;
     38     for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++) fa[x][i+1]=fa[fa[x][i]][i];
     39     for(int i=egh[x];i;i=eg[i][1]){
     40         int b=eg[i][0];if(b==fa[x][0]) continue;
     41         fa[b][0]=x;
     42         dep[b]=dep[x]+1;dfs(b);
     43     }
     44     dfn[x][1]=++tot;id[tot]=x;
     45 }
     46 
     47 inline int getlca(int x,int y){
     48     if(dep[x]<dep[y]) swap(x,y);
     49     for(int i=19;i>=0;i--){
     50         if(fa[x][i]&&dep[fa[x][i]]>=dep[y]) x=fa[x][i];
     51     }
     52     if(x==y) return x;
     53     for(int i=19;i>=0;i--){
     54         if(fa[x][i]&&fa[y][i]&&fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
     55     }
     56     return fa[x][0];
     57 }
     58 
     59 inline bool cmp(Node a,Node b){
     60     return (a.l/Blk==b.l/Blk)?((a.r/Blk==b.r/Blk?(a.i<b.i):a.r<b.r)):a.l<b.l;
     61 }
     62 
     63 inline ll inc(int c){
     64     return 1ll*val[c]*lik[++cnt[c]];
     65 }
     66 
     67 inline ll dec(int c){
     68     return -1ll*val[c]*lik[cnt[c]--];
     69 }
     70 
     71 inline ll deal(int x){
     72     // printf("DEAL:%d
    ",x);
     73     flag[x]^=1;
     74     if(flag[x]) return inc(col[x]);
     75     else return dec(col[x]);
     76 }
     77 
     78 inline ll change(int x,int y){
     79     ll re=0;
     80     if(flag[x]) re+=dec(col[x])+inc(y); 
     81     // printf("CG:%d %d %d %d
    ",x,y,col[x],re);
     82     col[x]=y;
     83     return re;
     84 }
     85 
     86 int main(){
     87     //freopen("","r",stdin);
     88     N=rd(),M=rd(),Q=rd();
     89     for(int i=1;i<=M;i++) val[i]=rd();
     90     for(int i=1;i<=N;i++) lik[i]=rd();
     91     for(int i=1;i<N;i++){
     92         int a=rd(),b=rd();
     93         adeg(a,b),adeg(b,a);
     94     }
     95     for(int i=1;i<=N;i++) col[i]=rd();
     96     dep[1]=1;dfs(1);
     97     // for(int i=1;i<=tot;i++) printf("~%d %d
    ",i,id[i]);
     98     for(int i=1;i<=Q;i++){
     99         int a=rd(),b=rd(),c=rd();
    100         if(!a) cg[++oct][0]=b,cg[oct][1]=c,cg[oct][2]=col[b],col[b]=c;
    101         else{
    102             if(dfn[b][0]>dfn[c][0]) swap(b,c);
    103             int lca=getlca(b,c);
    104             if(lca==b) qr[++qct]=Node(dfn[b][0],dfn[c][0],lca,oct,i);
    105             else qr[++qct]=Node(dfn[b][1],dfn[c][0],lca,oct,i);
    106         }
    107     }
    108     sort(qr+1,qr+qct,cmp);
    109     ll now=0;int l=1,r=0,t=oct;
    110     for(int i=1;i<=qct;i++){//if(i==2) continue;
    111         int x=qr[i].l,y=qr[i].r,z=qr[i].t;
    112         while(t<z) ++t,now+=change(cg[t][0],cg[t][1]);
    113         while(t>z) now+=change(cg[t][0],cg[t][2]),t--;
    114         while(r<y) now+=deal(id[++r]);
    115         while(r>y) now+=deal(id[r--]);
    116         while(l<x) now+=deal(id[l++]); 
    117         while(l>x) now+=deal(id[--l]);
    118         ans[qr[i].i]=now;
    119         if(qr[i].x!=id[qr[i].l]) ans[qr[i].i]+=deal(qr[i].x),deal(qr[i].x);
    120     }
    121     for(int i=1;i<=Q;i++) if(ans[i]) printf("%lld
    ",ans[i]);
    122     return 0;
    123 }
  • 相关阅读:
    Mybatis-plugin插件的使用
    SpringBoot整合mybatis-pagehelper实现分页
    springboot打war包
    keepalived1.4.0安装启动卸载
    六、nginx 搭建高可用集群
    五、nginx的动静分离
    四、nginx的负载均衡
    linux中mysql忘记root密码如何登陆
    十分钟到你了解OpenStack--nova组件
    docker 中 add 和 copy 的区别
  • 原文地址:https://www.cnblogs.com/Ressed/p/9997453.html
Copyright © 2011-2022 走看看