分块练习(莫队和值域分块)

主要是由莫队,线段树,树状数组构成

1.下标分块
/*莫队算法,莫队算法是将答案分块处理的离线算法,按照询问区间的出现的先后进行排序,
 * 这个算法自带一种玄学优化,两者左端点所属块如果不同则按照快大小进行排序
 * 如果左端点所属块相同,则看左端点所属块的奇偶性进行排序,奇则按照右端点从小到大,偶则按照右端点从大到小
 * 注意再次存储答案的时候不要使用map,会对答案的时间复杂度有影响
 * */
#include<bits/stdc++.h>
//#pragma GCC optimize(2)
//#define int long long
using namespace std;
typedef struct G{
    int first,second,id;
}PII;
const int N=2e6+10;
int d[N],pnr[N];
long long cnt[N];
vector<PII>v;
int ms[N];
long long sum=0;
bool cmp(PII a,PII b)
{
   return (pnr[a.first]^pnr[b.first])?(a.first<b.first):(pnr[a.first]&1)?a.second<b.second:a.second>b.second;
}
void add(int a,int var)
{
    sum-=(long long)ms[d[a]]*ms[d[a]]*d[a];
    ms[d[a]]+=var;
    sum+=(long long)ms[d[a]]*ms[d[a]]*d[a];
}

void sove()
{
    int n,m;
    cin>>n>>m;
    int t=sqrt(n);
    for(int i=1;i<=n;i++)cin>>d[i],pnr[i]=i/t+1;
    for(int i=1;i<=m;i++)
    {int a,b;
        cin>>a>>b;
        v.push_back({a,b,i});
    }
    int ll=0,rr=0;
    sort(v.begin(),v.end(),cmp);
    for(auto [l,r,id]:v)
    {
        while(l<ll)add(--ll,1);
        while(l>ll)add(ll++,-1);
        while(r>rr)add(++rr,1);
        while(r<rr)add(rr--,-1);
        cnt[id]=sum;
    }
    for(int i=1;i<=m;i++)cout<<cnt[i]<<"\n";
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t=1;
    sove();
}
2.值域分块
/*
值域分块(Range Partitioning)是一种数据分区技术,常用于数据库管理系统中的数据存储和查询优化。它通过将数据集按照特定的值范围进行划分,使得每个分区中的数据具有相似的值域。这样一来,在执行查询时,可以仅对包含目标值范围的分区进行搜索,提高查询效率。

值域分块的过程如下:

首先,确定要分块的字段,通常是一个数值型或日期型的字段。
然后,确定每个分区的大小或范围。可以根据数据的分布情况和查询需求来确定。
将数据集按照指定的字段值范围进行划分,每个分区包含在某个值范围内的数据。
对每个分区进行索引,以支持快速查询。
值域分块的好处是能够减少数据的搜索范围,提高查询效率。当查询条件与某个特定的值范围相关时,只需要搜索包含该值范围的分区,而不用搜索整个数据集。这种分块方式适用于数据量较大且分布不均匀的情况,可以充分利用硬件资源,提升系统性能。

需要注意的是,值域分块需要根据实际情况进行合理的设计和调整,以适应数据集的变化和查询需求的变化。同时,在进行值域分块时,还需要考虑分区的数量和大小,以平衡查询效率和存储开销之间的关系。
*/
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
//c记录数值,cnt元素利用次数,pur块
int c[N],cnt[N],pur[N],pos[N],h[N];
vector<int>v;
vector<pair<int,int>>q[N];
int ans[N];
void  add(int l,int a)
{
    cnt[l]++;
    h[pur[l]]++;
}
int  DER(int x)
{
    int sum=0;
    for(int i=x;pur[i]==pur[x]&&x>0;i--)sum+=cnt[i];
    for(int i=pur[x]-1;i>=0;i--)sum+=h[i];
    return sum;
}
void solve() {
    int n,m;
    cin >> n ;
    int ts=sqrt(n);
    //输入
    for (int i = 1; i <= n; i++) {
        int a;
        cin >> a;
        pur[i]=i/ts+1;
        c[i]=a;
        q[i].clear();
        pos[i]=0;
        cnt[i]=h[i]=0;
    }
    cin>>m;
    for(int i =1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        q[b].push_back({a,i});
    }
    int sum=0;
    for(int i=1;i<=n;i++) {
        {
           for(auto it:v)
           {
               int t=it-c[i];
               if(t>n)break;
               if(t<=0)continue;
               if(pos[t]) {
                   add(pos[t], 1);
                   sum++;
               }
           }
        //   cout<<sum<<" ";

           for(auto [l,id]:q[i])ans[id]=sum-DER(l-1);
           pos[c[i]]=i;
        }
    }
    for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
}
signed main ()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    //freopen("C:/Users/26470/Desktop/1002.in","r",stdin);
   //freopen("C:/Users/26470/Desktop/1.in","w",stdout);
    int t;
    for(int i=1;i<=500;i++){
        v.push_back(i*i);
    }
    cin>>t;
    while(t--)solve();
}

问题 - 86D - 代码强制 (codeforces.com)

A-Jujubesister_2023牛客暑期多校训练营5 (nowcoder.com)

问题 - 7337 (hdu.edu.cn)

Problem - 474F - Codeforces

E. XOR and Favorite Number

E. Xenia and Tree

//树上莫队感觉就是将树dfs序话,在进行莫队处理
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>h[N];
int l[N],r[N],ti;
int tr[N],p[N],ans[N];
int n,m;
struct G{
    int id,l,r,x;
};
void bfs(int a,int fa){
    l[a]=r[a]=++ti;
    for(auto it:h[a]){
        if(it==fa)continue;
        bfs(it,a);
    }
    r[a]=ti;
  //  cout<<a<<" "<<r[a]<<" "<<l[a]<<"\n";
}
void add(int x,int value){
    while(x<=n)tr[x]+=value,x+=x&-x;
}
int Sum(int x){
    int sum=0;
    while(x>0)sum+=tr[x],x-=x&-x;
    return sum;
}
void sove(){
    ti=0;
    cin>>n>>m;
    int ts=sqrt(n);
    for(int i=1;i<=n;i++)h[i].clear(),tr[i]=0;
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        h[a].push_back(b);
        h[b].push_back(a);
    }
    bfs(1,0);
    vector<G>q;
    for(int i=1;i<=n;i++)cin>>p[i];
    for(int i=1;i<=m;i++){
        int a,b,x;
        cin>>a>>b>>x;
        q.push_back({i,a,b,x});
    }
    sort(q.begin(),q.end(),[&](auto a,auto b){
        if(a.l/ts!=b.l/ts)return a.l<b.l;
        else return a.r>b.r;
    });
    int la=1,ra=0;
    for(auto [id,ll,rr,x]:q){
        while(la<ll)add(l[p[la++]],-1);
        while(la>ll)add(l[p[--la]],1);
        while(ra>rr)add(l[p[ra--]],-1);
        while(ra<rr)add(l[p[++ra]],1);
//        cout<<tr[1]<<" "<<tr[2]<<" "<<tr[3]<<"??\n";
        ans[id]=Sum(r[x])-Sum(l[x]-1);
  //      cout<<Sum(r[x])<<" "<<r[x]<<" ";
    //    cout<<Sum(l[x]-1)<<" "<<l[x]-1<<" ";
      //  cout<<ans[id]<<" "<<id<<"\n";
    }
    for(int i=1;i<=m;i++)puts(ans[i]?"YES":"NO");
}
int main ()
{
    int t=1;
    cin>>t;
    while(t--)sove();
}

 G. Unusual Entertainment

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值