主要是由莫队,线段树,树状数组构成
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)
//树上莫队感觉就是将树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();
}