C116 莫隊二次離線 P4887 莫隊二次離線

董晓發表於2024-04-15

影片連結:C116 莫隊二次離線 P4887 莫隊二次離線_嗶哩嗶哩_bilibili

Luogu P4887 【模板】莫隊二次離線(第十四分塊(前體))

// 莫隊二次離線 O(n*sqrt(n)+n*C(k,14))
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

const int N=100005;
int n,m,k,B,block[N],a[N],t[N],pre[N];
long long ans[N];
vector<int> b;  //二進位制中1的個數為k的數
struct F{
  int id,l,r,z;
};
vector<F> f[N]; //待求貢獻的資訊
struct Q{
  int id,l,r;
  long long ans;
  bool operator<(Q &x){
    if(block[l]!=block[x.l])return l<x.l;
    return r<x.r;
  }
}q[N];

int count(int x){ //x的二進位制中1的個數
  int s=0;
  while(x) s+=x&1,x>>=1;
  return s;
}
int main(){
  scanf("%d%d%d",&n,&m,&k); B=sqrt(n);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i),block[i]=(i-1)/B+1;
  for(int i=1,l,r;i<=m;i++)
    scanf("%d%d",&l,&r),q[i]={i,l,r};
  sort(q+1,q+m+1);
  for(int i=0;i<1<<14;++i)
    if(count(i)==k)b.push_back(i); //最多C(7,14)=3432
  for(int i=1;i<=n;i++){
    pre[i]=t[a[i]];//a1~a[i-1]與ai異或有k個1的數的個數
    for(auto x:b) ++t[a[i]^x];
  }
  for(int i=1,l=1,r=0;i<=m;i++){ //莫隊
    //r右移:f(l,x-1)=f(1,x-1)-f(1,l-1), x~[r+1,qr]
    if(r<q[i].r) f[l-1].push_back({i,r+1,q[i].r,-1});
    while(r<q[i].r) q[i].ans+=pre[++r];
    //r左移:-f(l,x-1)=-(f(1,x-1)-f(1,l-1)), x~[qr+1,r]
    if(r>q[i].r) f[l-1].push_back({i,q[i].r+1,r,1});
    while(r>q[i].r) q[i].ans-=pre[r--];
    //l左移:f(x+1,r)=f(1,r)-f(1,x), x~[ql,l-1]
    if(l>q[i].l) f[r].push_back({i,q[i].l,l-1,1});
    while(l>q[i].l) q[i].ans-=pre[--l]+!k;
    //l右移:-f(x+1,r)=-(f(1,r)-f(1,x)), x~[l,ql-1]
    if(l<q[i].l) f[r].push_back({i,l,q[i].l-1,-1});
    while(l<q[i].l) q[i].ans+=pre[l++]+!k;
  }
  //二次離線,累計f(1,l-1)和f(1,r)的貢獻
  memset(t,0,sizeof(t));
  for(int i=1,id,l,r,z;i<=n;i++){ //掃描ai
    for(auto& x:b) ++t[a[i]^x];   //與ai配對的數均+1
    for(auto& y:f[i]){            //以ai為邊界的f
      for(int x=y.l;x<=y.r;x++)
        q[y.id].ans+=y.z*t[a[x]]; //累計配對貢獻
    }
  }
  //後一個查詢是前一個查詢的增量,故求字首和
  for(int i=2;i<=m;i++)q[i].ans+=q[i-1].ans;
  for(int i=1;i<=m;i++)ans[q[i].id]=q[i].ans;
  for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}

// 莫隊二次離線 O(n*sqrt(n)+n*C(k,14))
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <tuple>
using namespace std;

const int N=100005;
int n,m,k,B,block[N],a[N],t[N],pre[N]; 
long long ans[N];
vector<int> b;   //二進位制中1的個數為k的數
vector<tuple<int,int,int,int>> f[N]; //待求貢獻的資訊
struct Q{
  int id,l,r;
  long long ans;
  bool operator<(Q &x){
    if(block[l]!=block[x.l])return l<x.l;
    return r<x.r;
  }
}q[N];

int main(){
  scanf("%d%d%d",&n,&m,&k); B=sqrt(n);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i),block[i]=(i-1)/B+1;
  for(int i=1,l,r;i<=m;i++)
    scanf("%d%d",&l,&r),q[i]={i,l,r};
  sort(q+1,q+m+1);
  for(int i=0;i<1<<14;++i) //b內最多C(7,14)=3432
    if(__builtin_popcount(i)==k)b.push_back(i); 
  for(int i=1;i<=n;i++){
    pre[i]=t[a[i]];//a1~a[i-1]與ai異或有k個1的數的個數
    for(auto x:b) ++t[a[i]^x];
  }
  
  for(int i=1,l=1,r=0;i<=m;i++){ //莫隊
    //r右移:f(l,x-1)=f(1,x-1)-f(1,l-1), x~[r+1,qr]
    if(r<q[i].r) f[l-1].emplace_back(i,r+1,q[i].r,-1);
    while(r<q[i].r) q[i].ans+=pre[++r];
    //r左移:-f(l,x-1)=-(f(1,x-1)-f(1,l-1)), x~[qr+1,r]
    if(r>q[i].r) f[l-1].emplace_back(i,q[i].r+1,r,1);
    while(r>q[i].r) q[i].ans-=pre[r--];
    //l左移:f(x+1,r)=f(1,r)-f(1,x), x~[ql,l-1]
    if(l>q[i].l) f[r].emplace_back(i,q[i].l,l-1,1);
    while(l>q[i].l) q[i].ans-=pre[--l]+!k;
    //l右移:-f(x+1,r)=-(f(1,r)-f(1,x)), x~[l,ql-1]
    if(l<q[i].l) f[r].emplace_back(i,l,q[i].l-1,-1);
    while(l<q[i].l) q[i].ans+=pre[l++]+!k; 
  }
  //二次離線,累計f(1,l-1)和f(1,r)的貢獻
  memset(t,0,sizeof(t));
  for(int i=1,id,l,r,z;i<=n;i++){ //掃描ai
    for(auto& x:b) ++t[a[i]^x];   //與ai配對的數均+1
    for(auto& y:f[i]){            //以ai為邊界的f
      std::tie(id,l,r,z)=y;       //元組的賦值
      for(int x=l;x<=r;x++)       //累計配對貢獻
        q[id].ans+=z*t[a[x]];
    }
  }
  //後一個查詢是前一個查詢的增量,故求字首和
  for(int i=2;i<=m;i++)q[i].ans+=q[i-1].ans;
  for(int i=1;i<=m;i++)ans[q[i].id]=q[i].ans;
  for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}

P5047 [Ynoi2019 模擬賽] Yuno loves sqrt technology II - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

P5501 [LnOI2019] 來者不拒,去者不追 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

相關文章