分块
分块
将数组分为N½块,算出每块对应的满足条件的值,在暴力的基础上提升效率。
蒲公英
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列a1,a2,…,ana1,a2,…,an,其中aiai为一个正整数,表示第 i 棵蒲公英的种类编号。
而每次询问一个区间 [l,r] ,你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
输入格式
第一行两个整数n,m,表示有 n 株蒲公英,m 次询问。
接下来一行 n 个空格隔开的整数aiai,表示蒲公英的种类。
再接下来 m 行每行两个整数l0,r0l0,r0,我们令上次询问的结果为 x(如果这是第一次询问,则 x=0)。
令l=(l0l0+x-1) mod n+1,r=(r0r0+x-1) mod n+1,如果l>r,则交换l,r。
最终的询问区间为[l,r]。
输出格式
输出 m 行。
每行一个整数,表示每次询问的结果。
数据范围
1≤n≤400001≤n≤40000,
1≤m≤500001≤m≤50000,
1≤ai≤1091≤ai≤109
输入样例:
6 3
1 2 3 2 1 2
1 5
3 6
1 5
输出样例:
1
2
1
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10,T = 500;
int n, m, block;
int a[N], b[N], f[N], tot;
int d[1000][1000];
int g[T][N];
int ct[N];
int num[N],tmp[N];
void build()
{
block = (int)sqrt(1.0*n);
for (int i = 1; i <= n; i++)
b[i] = (i - 1) / block + 1;
}
void pre(int x)
{
int top = 0;
int mx = -1, ans = 0;
for (int i = (x - 1)*block + 1; i <= n; i++)
{
g[x][a[i]]++;
ct[a[i]]++;
if (ct[a[i]] == 1){
tmp[++top] = a[i];
}
if (ct[a[i]] > mx || (ct[a[i]] == mx&&a[i] < ans))
{
ans = a[i];
mx = ct[a[i]];
}
d[x][b[i]] = ans;
}
while (top)
{
ct[tmp[top--]] = 0;
}
}
int query(int l, int r)
{
int p = b[l], q = b[r];
int ans = 0, cnt = 0, top = 0;
int up = b[l] * block;
if (q - p < 2)
{
for (int i = l; i<= r; i++)
{
++ct[a[i]];
if (ct[a[i]] == 1){
tmp[++top] = a[i];
}
}
while (top)
{
int x = tmp[top--];
if (cnt < ct[x] || (cnt == ct[x] && x < ans))
{
ans = x;
cnt = ct[x];
}
ct[x] = 0;
}
return ans;
}
for (int i = l; i <= up; i++)
{
++ct[a[i]];
if (ct[a[i]] == 1)
{
tmp[++top] = a[i];
num[a[i]] = g[p + 1][a[i]] - g[q][a[i]];
}
}
for (int i = (b[r] - 1)*block + 1; i <= r; i++)
{
++ct[a[i]];
if (ct[a[i]] == 1){
tmp[++top] = a[i];
num[a[i]] = g[p + 1][a[i]] - g[q][a[i]];
}
}
ans = d[b[l] + 1][b[r] - 1];
num[ans]=g[p + 1][ans] - g[q][ans];
cnt = ct[ans]+num[ans];
while (top)
{
int x = tmp[top--];
ct[x] += num[x];
if (cnt < ct[x] || (cnt == ct[x] && x < ans))
{
ans = x;
cnt = ct[x];
}
ct[x] = 0;
num[x]=0;
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
f[i] = a[i];
}
build();
sort(f + 1, f + n + 1);
int N = unique(f + 1, f + n + 1) - f - 1;
for (int i = 1; i <= n; i++)
{
a[i] = lower_bound(f + 1, f + N + 1, a[i]) - f;
}
int ans = 0;
for (int i = 1; i <= b[n]; i++)
pre(i);
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
l = (l + ans - 1) % n + 1;
r = (r + ans - 1) % n + 1;
if (l>r) swap(l, r);
ans = f[query(l, r)];
printf("%d\n", ans);
}
return 0;
}
磁力块
在一片广袤无垠的原野上,散落着N块磁石。
每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。
若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
小取酒带着一块自己的磁石L来到了这片原野的(x0,y0)(x0,y0)处,我们可以视磁石L的坐标为(x0,y0)(x0,y0)。
小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。
在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)(x0,y0)处吸引更多的磁石。
小取酒想知道,他最多能获得多少块磁石呢?
输入格式
第一行五个整数x0,y0,pL,rL,Nx0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。
输出格式
输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)。
数据范围
1≤N≤250000
−109≤x,y≤109
1≤m,p,r≤109
分块+广度优先搜索 O(Nn√)O(Nn)
首先我们看得到的条件是.质量≤磁力,距离≤吸引半径质量≤磁力,距离≤吸引半径
整体质量升序,局部距离升序。
开一个队列保存吸引到且未被使用的磁石。
设队头磁铁石为H,那么必然存在一个K,满足一下这些性质
第1~K-1段中所有的磁石质量都不大与H的磁力
第K+1段之后的磁铁石质量都大于H的磁力
则1~K-1的块,如果距离大于H的距离,则跳到下一块,否则则判断该磁石是否已经被吸引,未被吸引就加入队列。
对于第K块,如果距离大于H的距离,则结束,否则则判断该磁石是否已经被吸引以及质量是否不超过H的磁力,如果满足,就加入队列。
那么我们从左往右数,发现如果无法吸引过来了,那么下一次我们直接把这段的开头位置移到这个无法吸引的位置。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6;
const int w=500;
struct node
{
ll d,r;
ll m,p;
} a[N];
ll D[N],x0,y_0,now,L[N],R[N],v[N],n,tot,l,r,p,x,y;
queue<ll> q;
bool cmp_d(node a,node b)
{
return a.d<b.d;
}
bool cmp_m(node a,node b)
{
return a.m<b.m;
}
int main()
{
cin>>x0>>y_0>>a[0].p>>a[0].r>>n;
a[0].r*=a[0].r;//第一块磁铁
for(int i=1;i<=n;i++)
{
cin>>x>>y>>a[i].m>>a[i].p>>a[i].r;
a[i].r*=a[i].r;
a[i].d=(x0-x)*(x0-x)+(y_0-y)*(y_0-y);//计算距离
}
sort(a+1,a+1+n,cmp_d);
for(ll i=1;i<=n;i+=w)
{
L[++tot]=i;
R[tot]=min(n,i+w-1);//计算L和R的范围,也就是第i大块的范围
D[tot]=a[R[tot]].d;
sort(a+L[tot],a+R[tot]+1,cmp_m);//大块内则排序
}
q.push(0);
ll ans=1;
while(q.size())
{
ll l=q.front();
now=a[l].r;
p=a[l].p;
q.pop();
for(ll i=1;i<=tot;i++)
{
if (D[i]>now)
{
for(ll j=L[i];j<=R[i];j++)
if (!v[j] && a[j].d<=now && a[j].m<=p)//没有吸过来,而且在范围内
{
q.push(j);
ans++;
v[j]=1;
}
break;
}
while(L[i]<=R[i] && a[L[i]].m<=p)//加入一块磁铁石,然后把则块磁铁石可以吸收的磁铁石放进去
{
if (!v[L[i]])//没有被访问
{
q.push(L[i]);
ans++;
}
++L[i];
}
}
}
cout<<ans-1;//不算刚开始的赠送磁石
}
输入样例:
0 0 5 10 5
5 4 7 11 5
-7 1 4 7 8
0 2 13 5 6
2 -3 9 3 4
13 5 1 9 9
输出样例:
3
数列分块入门 1(区间加法,单点查值)!

由于太模板就直接树状数组了。
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int n,a[N],c[N];
void add(int x,int y)
{
for(;x<=n;x+=x&-x) c[x]+=y;
}
int ask(int x)
{
int res=0;
for(;x;x-=x&-x) res+=c[x];
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
for(int i=1,opt,l,r,c;i<=n;++i)
{
scanf("%d %d %d %d",&opt,&l,&r,&c);
if(opt) printf("%d\n",ask(r)+a[r]);
else add(l,c),add(r+1,-c);
}
}
数列分块入门 2(区间加法,区间查找比x小的值)

内联函数,将A的每个块排序,val升序,val相同id升序。
lower_bound()函数快速查询在范围内的每个块比x小的数的个数。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxN = 5e4 + 7;
int N, Q, len, s;
struct node
{
int val, id;
node(int a=0, int b=0):val(a), id(b) {}
friend bool operator < (node e1, node e2) { return e1.val < e2.val; }
}a[maxN];
struct K
{
int l, r, sum;
K(int a=0, int b=0, int c=0):l(a), r(b), sum(c) {}
}t[maxN];
inline void update(int ql, int qr, int w)
{
int st = (ql - 1) / len + 1, ed = (qr - 1) / len + 1;
if(st == ed)
{
for(int i=t[st].l; i<=t[st].r; i++)
{
if(a[i].id >= ql && a[i].id <= qr) a[i].val += w;
}
sort(a + t[st].l, a + t[st].r + 1);
return;
}
for(int i=t[st].l; i<=t[st].r; i++)
{
if(a[i].id >= ql && a[i].id <= qr) a[i].val += w;
}
sort(a + t[st].l, a + t[st].r + 1);
for(int i=t[ed].l; i<=t[ed].r; i++)
{
if(a[i].id >= ql && a[i].id <= qr) a[i].val += w;
}
sort(a + t[ed].l, a + t[ed].r + 1);
for(int i=st + 1; i <= ed - 1; i++) t[i].sum += w;
}
inline int query(int ql, int qr, ll x)
{
int ans = 0, add;
ll tmp;
int st = (ql - 1) / len + 1, ed = (qr - 1) / len + 1;
if(st == ed)
{
tmp = x - t[st].sum;
for(int i=t[st].l; i<=t[st].r; i++)
{
if(a[i].val >= tmp) break;
if(a[i].id >= ql && a[i].id <= qr) ans++;
}
return ans;
}
tmp = x - t[st].sum;
for(int i=t[st].l; i<=t[st].r; i++)
{
if(a[i].val >= tmp) break;
if(a[i].id >= ql && a[i].id <= qr) ans++;
}
tmp = x - t[ed].sum;
for(int i=t[ed].l; i<=t[ed].r; i++)
{
if(a[i].val >= tmp) break;
if(a[i].id >= ql && a[i].id <= qr) ans++;
}
node now = node((int)tmp, 0);
for(int i=st + 1; i <= ed - 1; i++)
{
tmp = x - t[i].sum;
now = node((int)tmp, 0);
add = (int)(lower_bound(a + t[i].l, a + t[i].r + 1, now) - a - t[i].l);
ans += add;
}
return ans;
}
int main()
{
scanf("%d", &N); Q = N;
len = sqrt(N);
s = N / len + (N % len == 0 ? 0 : 1);
for(int i=1; i<=N; i++)
{
scanf("%d", &a[i].val);
a[i].id = i;
}
for(int i=1; i<=s; i++)
{
t[i].l = (i - 1) * len + 1;
t[i].r = i * len;
}
t[s].r = N;
for(int i=1; i<=s; i++) sort(a + t[i].l, a + t[i].r + 1);
int op, l, r; ll c;
while(Q--)
{
scanf("%d%d%d%lld", &op, &l, &r, &c);
if(op)
{
printf("%d\n", query(l, r, c * c));
}
else
{
update(l, r, (int)c);
}
}
return 0;
}
数列分块入门 3(区间加法,查询前驱)

set快速查询块内大于等于x的第一个数,然后it--得到小于x的最后一个数。
集合指针的声明操作:
set<int>::iterator it;
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,siz,num,a[N];
struct
{
int l,r,sum;
}t[N];
set<int>s[N];
void change(int l,int r,int c)
{
int st=(l-1)/siz+1,ed=(r-1)/siz+1;
if(st==ed)
{
for(int i=l;i<=r;++i)
a[i]+=c;
s[st].clear();
for(int i=t[st].l;i<=t[st].r;++i)
s[st].insert(a[i]);
}
else
{
if(l!=t[st].l)
{
for(int i=l;i<=t[st].r;++i)
a[i]+=c;
s[st].clear();
for(int i=t[st].l;i<=t[st].r;++i)
s[st].insert(a[i]);
st++;
}
if(r!=t[ed].r)
{
for(int i=t[ed].l;i<=r;++i)
a[i]+=c;
s[ed].clear();
for(int i=t[ed].l;i<=t[ed].r;++i)
s[ed].insert(a[i]);
ed--;
}
for(int i=st;i<=ed;++i) t[i].sum+=c;
}
}
int ask(int l,int r,int c)
{
int ans=-1,st=(l-1)/siz+1,ed=(r-1)/siz+1,x;
if(st==ed)
{
x=t[st].sum;
for(int i=l;i<=r;++i)
if(a[i]+x<c) ans=max(ans,a[i]+x);
}
else
{
if(l!=t[st].l)
{
x=t[st].sum;
for(int i=l;i<=t[st].r;++i)
if(a[i]+x<c) ans=max(ans,a[i]+x);
st++;
}
if(r!=t[ed].r)
{
x=t[ed].sum;
for(int i=t[ed].l;i<=r;++i)
if(a[i]+x<c) ans=max(ans,a[i]+x);
ed--;
}
set<int>::iterator it;
for(int i=st;i<=ed;++i)
{
x=c-t[i].sum;
it = s[i].lower_bound(x);
if (it == s[i].begin())continue;
it--;
ans=max(*it+t[i].sum,ans);
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
siz=sqrt(n);
num=n/siz;
for(int i=1;i<=num;++i)
{
t[i].l=siz*(i-1)+1;
t[i].r=siz*i;
}
if(n%siz)
{
num++;
int k=n/siz+1;
t[k].l=siz*(n/siz)+1,
t[k].r=n;
}
for(int i=1;i<=num;++i)
for(int j=t[i].l;j<=t[i].r;++j)
s[i].insert(a[j]);
for(int i=1,opt,l,r,c;i<=n;++i)
{
scanf("%d %d %d %d",&opt,&l,&r,&c);
if(opt) printf("%d\n",ask(l,r,c));
else change(l,r,c);
}
}
数列分块入门 4(区间加法,区间求和)

粗暴一点就完事儿了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4+7;
typedef long long ll;
inline int read()
{
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int a[maxn],l[maxn],r[maxn],belong[maxn];
ll sum[maxn],add[maxn];
int n,num,block;
void build()
{
block = sqrt(n);
num = n / block; if(n % block) num++;
for(int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
r[num] = n;
for(int i = 1; i <= n; i++)
{
belong[i] = (i - 1) / block + 1;
sum[belong[i]] += a[i];
}
}
void update(int x,int y,int c)
{
int t1 = belong[x], t2 = belong[y];
for(int i = x; i <= min(r[t1], y); i++)
{
a[i] += c;
sum[t1] += c;
}
if(t1 != t2) for(int i = l[t2]; i <= y; i++)
{
a[i] += c;
sum[t2] += c;
}
for(int i = t1 + 1; i < t2; i++)
sum[i] += block * c, add[i] += c;
}
ll query(int x,int y,int c)
{
ll ans = 0;
int t1 = belong[x], t2 = belong[y];
for(int i = x; i <= min(r[t1], y); i++)
ans += a[i] + add[t1];
if(t1 != t2) for(int i = l[t2]; i <= y; i++)
ans += a[i] + add[t2];
for(int i = t1 + 1; i < t2; i++)
ans += sum[i];
return ans % (c + 1);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1; i <= n; i++) a[i] = read();
build();
for(int i = 1; i <= n; i++)
{
int op = read(), l = read(), r = read(), c = read();
if(op == 1) printf("%lld\n", query(l,r,c));
else update(l,r,c);
}
}
return 0;
}
数列分块入门 5(区间开方,区间求和)!
太模板了,直接复制粘贴花神游历各国。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+5;
ll n,m,a[N];
struct
{
ll l,r,flag,val;
}t[N<<3];
inline ll read()
{
char dd;
ll res=0,w=1;
while((dd=getchar())&&(dd>'9'||dd<'0'))
if(dd=='-') w=-1;
res=dd-'0';
while((dd=getchar())&&dd<='9'&&dd>='0') res=res*10+dd-'0';
return res;
}
void build(ll l,ll r,ll p)
{
t[p].l=l;
t[p].r=r;
if(l==r)
{
t[p].val=a[l];
t[p].flag=(t[p].val<=1);
return;
}
ll m=(l+r)/2;
build(l,m,p*2);
build(m+1,r,p*2+1);
t[p].val=t[p*2].val+t[p*2+1].val;
t[p].flag=t[p*2].flag&t[p*2+1].flag;
}
ll ask(ll l,ll r,ll p)
{
if(t[p].l>=l&&t[p].r<=r) return t[p].val;
ll ans=0,m=(t[p].l+t[p].r)/2;
if(l<=m) ans+=ask(l,r,p*2);
if(r>m) ans+=ask(l,r,p*2+1);
return ans;
}
void change(ll l,ll r,ll p)
{
if(t[p].flag) return;
if(t[p].l==t[p].r)
{
t[p].val=sqrt(t[p].val);
t[p].flag=(t[p].val<=1);
return;
}
ll m=(t[p].l+t[p].r)/2;
if(l<=m) change(l,r,p*2);
if(r>m) change(l,r,p*2+1);
t[p].val=t[p*2].val+t[p*2+1].val;
t[p].flag=t[p*2].flag&t[p*2+1].flag;
}
int main()
{
n=read();
for(ll i=1;i<=n;++i) a[i]=read();
build(1,n,1);
ll x,l,r,c;
for(int i=1;i<=n;++i)
{
x=read();l=read();r=read();c=read();
if(l>r) swap(l,r);
if(x==1) printf("%lld\n",ask(l,r,1));
else change(l,r,1);
}
}
数列分块入门 6(单点插入,单点查询)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
int n, d, nn;
int a[MAXN<<1];
vector<int> v[1005];
inline void mer(){//把所有元素还原到a数组中
n = 0;
for ( int i = 1; i <= d + 1; ++i ){
if ( v[i].empty() ) break;
for ( int j = 0; j < v[i].size(); ++j ) a[++n] = v[i][j];
v[i].clear();
}
}
inline void div(){//把a数组元素分配到各个块中
d = sqrt(n);
for ( int i = 1; i <= n; ++i ) v[( i - 1 ) / d + 1].push_back(a[i]);
}
inline int Get( int wh ){
for ( int i = 1; i <= d + 1; ++i ){
if ( wh > v[i].size() ) wh -= v[i].size();
else return v[i][wh - 1];
}
}
inline void Ins( int wh, int x ){
for ( int i = 1; i <= d + 1; ++i ){
if ( wh > v[i].size() ) wh -= v[i].size();
else{
v[i].insert( v[i].begin() + wh - 1, x );//插入~
if ( v[i].size() > 10 * d ) mer(), div();//重排
return;
}
}
}
int main(){
scanf( "%d", &n );
for ( int i = 1; i <= n; ++i ) scanf( "%d", &a[i] );
div();
nn = n;
for ( int i = 1; i <= nn; ++i ){
int opt, l, r, c;
scanf( "%d%d%d%d", &opt, &l, &r, &c );
if ( opt ) printf( "%d\n", Get(r) );
else Ins( l, r );
}
return 0;
}
数列分块入门 7(区间乘法,区间加法,单点询问)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define mod(x) (1ll * x) % 10007
int n, d;
int a[MAXN], b[MAXN], tg1[500], tg2[500];
inline void Push( int wh ){
for ( int i = ( wh - 1 ) * d + 1; i <= wh * d; ++i ) a[i] = mod( 1ll * a[i] * tg2[wh] + tg1[wh] );
tg1[wh] = 0; tg2[wh] = 1;
}
void Add( int l, int r, int c ){
if ( b[l] == b[r] ){
Push(b[l]);
for ( int i = l; i <= r; ++i ) a[i] = mod( a[i] + c );
return;
}
Push(b[l]);
for ( int i = l; b[i] == b[l]; ++i ) a[i] = mod( a[i] + c );
Push(b[r]);
for ( int i = r; b[i] == b[r]; --i ) a[i] = mod( a[i] + c );
for ( int i = b[l] + 1; i <= b[r] - 1; ++i ) tg1[i] = mod( tg1[i] + c );
}
void Mul( int l, int r, int c ){
if ( b[l] == b[r] ){
Push(b[l]);
for ( int i = l; i <= r; ++i ) a[i] = mod( a[i] * c );
return;
}
Push(b[l]);
for ( int i = l; b[i] == b[l]; ++i ) a[i] = mod( a[i] * c );
Push(b[r]);
for ( int i = r; b[i] == b[r]; --i ) a[i] = mod( a[i] * c );
for ( int i = b[l] + 1; i <= b[r] - 1; ++i ) tg1[i] = mod( tg1[i] * c ), tg2[i] = mod( tg2[i] * c );
}
int main(){
scanf( "%d", &n );
d = sqrt(n);
for ( int i = 1; i <= n; ++i ){
scanf( "%d", &a[i] );
b[i] = ( i - 1 ) / d + 1;
}
for ( int i = 1; i <= b[n]; ++i ) tg1[i] = 0, tg2[i] = 1;
for ( int i = 1; i <= n; ++i ){
int opt, l, r, c;
scanf( "%d%d%d%d", &opt, &l, &r, &c );
if ( opt == 0 ) Add( l, r, c );
if ( opt == 1 ) Mul( l, r, c );
if ( opt == 2 ) printf( "%d\n", mod(a[r] * tg2[b[r]] + tg1[b[r]]) );
}
return 0;
}
数列分块入门 8(区间询问c的个数,区间修改)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
int n, d;
int a[MAXN], b[MAXN], f[500];
bool v[500];
int FF( int x ){//取出x位置的值
return v[b[x]] ? f[b[x]] : a[x];
}
int fun( int l, int r, int c ){//计数&修改
int ans(0);
for ( int i = l; i <= r && i <= n; ++i ) ans += FF(i) == c, a[i] = c;
return ans;
}
int Get( int l, int r, int c ){
int ans(0);
if ( b[l] == b[r] ){
if ( v[b[l]] && f[b[l]] == c ) return r - l + 1;
if ( v[b[l]] ){
fun( ( b[l] - 1 ) * d + 1, l - 1, f[b[l]] );
fun( r + 1, b[l] * d, f[b[l]] );
}
ans = fun( l, r, c );
v[b[l]] = 0;
return ans;
}
if ( v[b[l]] ) fun( ( b[l] - 1 ) * d + 1, l - 1, f[b[l]] );
ans += fun( l, b[l] * d, c );
v[b[l]] = 0;
if ( v[b[r]] ) fun( r + 1, min( b[r] * d, n ), f[b[r]] );
ans += fun( ( b[r] - 1 ) * d + 1, r, c );
v[b[r]] = 0;
for ( int i = b[l] + 1; i <= b[r] - 1; ++i ){
if ( !v[i] ){
for ( int j = ( i - 1 ) * d + 1; b[j] == i; ++j ) ans += a[j] == c, a[j] = c;
v[i] = 1; f[i] = c;
} else{
if ( f[i] == c ) ans += d;
else f[i] = c;
}
}
return ans;
}
int main(){
scanf( "%d", &n );
d = (int)sqrt(n);
for ( int i = 1; i <= n; ++i ){
scanf( "%d", &a[i] );
b[i] = ( i - 1 ) / d + 1;
}
for ( int i = 1; i <= n; ++i ){
int l, r, c;
scanf( "%d%d%d", &l ,&r, &c );
printf( "%d\n", Get( l, r, c ) );
}
return 0;
}
数列分块入门 9(区间查询重数)/回滚莫队
#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
int n, m, T;
int a[MAXN], b[MAXN], c[MAXN];
int d, f[2000][2000];
int s[MAXN];
vector<int> p[MAXN];
int Count( int l, int r, int x ){
return upper_bound( p[x].begin(), p[x].end(), r ) - lower_bound( p[x].begin(), p[x].end(), l );
}
int Get( int l, int r ){
if ( b[l] == b[r] ){
int ans1(0), ans2(0);
for ( int i = l; i <= r; ++i ){
int t(Count( l, r, a[i] ));
if ( t > ans2 ) ans1 = a[i], ans2 = t;
if ( t == ans2 ) ans1 = min( ans1, a[i] );
}
return ans1;
}
int ans1(f[b[l] + 1][b[r] - 1]), ans2(Count( l, r, ans1 ));
for ( int i = l; b[l] == b[i]; ++i ){
int t(Count( l, r, a[i] ));
if ( t == ans2 ) ans1 = min( ans1, a[i] );
if ( t > ans2 ) ans1 = a[i], ans2 = t;
}
for ( int i = r; b[r] == b[i]; --i ){
int t(Count( l, r, a[i] ));
if ( t == ans2 ) ans1 = min( ans1, a[i] );
if ( t > ans2 ) ans1 = a[i], ans2 = t;
}
return ans1;
}
int main(){
scanf( "%d", &n );
d = 0;
while( ( 1 << d ) <= n ) d++;
d--;
d = (int)( n / sqrt( 2 * n * d ) );
for ( int i = 1; i <= n; ++i ){
scanf( "%d", &a[i] ); c[i] = a[i]; b[i] = ( i - 1 ) / d + 1;
}
sort( c + 1, c + n + 1 );//离散化
m = unique( c + 1, c + n + 1 ) - c - 1;
for ( int i = 1; i <= n; ++i ) a[i] = lower_bound( c + 1, c + m + 1, a[i] ) - c;
for ( int i = 1; i <= n; ++i ) p[a[i]].push_back(i);//每个元素都记录位置
for ( int i = 1; i <= b[n]; ++i ){
memset( s, 0, sizeof s );
int ans1(0), ans2(0);
for ( int j = ( i - 1 ) * d + 1; j <= n; ++j ){
s[a[j]]++;
if ( s[a[j]] == ans2 ) ans1 = min( ans1, a[j] );
if ( s[a[j]] > ans2 ) ans1 = a[j], ans2 = s[a[j]];
if ( b[j + 1] != b[j] ) f[i][b[j]] = ans1;
}
}
int x(0);
for ( int T = 1; T <= n; ++T ){
int l, r;
scanf( "%d%d", &l, &r );
int t(min( l, r )); r = max( l, r ); l = t;
printf( "%d\n", x = c[Get( l, r )] );
}
return 0;
}

浙公网安备 33010602011771号