分块

分块

将数组分为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;
}
posted @ 2020-10-23 19:10  林生。  阅读(141)  评论(0)    收藏  举报