数列分块入门 6~数列分块入门 9

2017: #6282. 数列分块入门 6

题目描述

给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及单点插入,单点询问,数据随机生成。

输入

第一行输入一个数字 nnn。

第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。

接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt、lll、rrr、ccc,以空格隔开。

若 opt=0\mathrm{opt} = 0opt=0,表示在第 lll 个数字前插入数字 rrr (ccc 忽略)。

若 opt=1\mathrm{opt} = 1opt=1,表示询问 ara_rar 的值(lll 和 ccc 忽略)。

输出

对于每次询问,输出一行一个数字表示答案。

样例输入 

1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

样例输出 

2
3

提示

对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1ans≤231−1。

#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define _ 0
#define LL long long
#define Space putchar(' ')
#define Enter putchar('\n')
#define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
#define fu(x,y,z)  for(int x=(y),x##end=z;x<x##end;x++)
#define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
#define fd(x,y,z)  for(int x=(y),x##end=z;x>x##end;x--)
#define mem(x,y)   memset(x,y,sizeof(x))
#ifndef olinr
inline char getc()
{
	static char buf[100001],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
template<typename T>inline void in(T &x)
{
	int f=1; char ch; x=0;
	while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
	while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
	x*=f;
}
const int inf=0x7fffffff;
int n,num;
struct K
{
	int a[2100],siz;
	K *nxt;
	K() {mem(a,0),siz=0,nxt=NULL;}
	void *operator new (size_t)
	{
		static K *S=NULL,*T=NULL;
		return (S==T&&(T=(S=new K[1024])+1024),S++);	
	}
};
K *beg=new K();
inline void init()
{
	in(n),num=std::sqrt(n);
	K *o=beg,*t;
	fuu(i,1,n)
	{
		if(o->siz==num) t=new K(),o->nxt=t,o=t;
		in(o->a[++o->siz]);
	}
}
inline void split(K *o)
{
	K *t=new K();
	int mid=(1+o->siz)>>1;
	fuu(i,mid+1,o->siz) t->a[++t->siz]=o->a[i];
	o->siz=mid;
	t->nxt=o->nxt,o->nxt=t;
}
inline void add(int pos,int key)
{
	K *o=beg;
	int now=0;
	while(now+o->siz<pos) now+=o->siz,o=o->nxt;
	int p=pos-now;
	fdd(i,o->siz,p+1) o->a[i+1]=o->a[i];
	o->a[p+1]=key;
	o->siz++;
	if(o->siz>=(num<<1)) split(o);
}
inline int query(int pos)
{
	K *o=beg;
	int now=0;
	while(now+o->siz<pos) now+=o->siz,o=o->nxt;
	return o->a[pos-now];
}
int main()
{
	init();
	int p,l,r,c;
	while(n--)
	{
		in(p),in(l),in(r),in(c);
		if(p==0) add(l-1,r);
		else printf("%d\n",query(r));
	}
	return ~~(0^_^0);
}

 

2018: #6283. 数列分块入门 7

题目描述

给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间乘法,区间加法,单点询问。

输入

第一行输入一个数字 nnn。

第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。

接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt、lll、rrr、ccc,以空格隔开。

若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字都加 ccc。

若 opt=1\mathrm{opt} = 1opt=1,表示将位于 [l,r][l, r][l,r] 的之间的数字都乘 ccc。

若 opt=2\mathrm{opt} = 2opt=2,表示询问 ara_rar 的值 mod 10007mod \ 10007mod10007(lll 和 ccc 忽略)。

输出

对于每次询问,输出一行一个数字表示答案。

样例输入 

7
1 2 2 3 9 3 2
0 1 3 1
2 1 3 1
1 1 4 4
0 1 7 2
1 2 6 4
1 1 6 5
2 2 6 4

样例输出 

3
100

提示

对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1ans≤231−1。

#include<bits/stdc++.h>
using namespace std;
# define ll long long
const int maxn =  2e6+100;
const int inf = 0x3f3f3f3f;
const int mod = 1e4+7;
ll l[maxn],r[maxn],belong[maxn];
ll add[maxn],a[maxn],sum[maxn],mul[maxn];
int n;
void buildblock()
{
    ll tmp=(ll)sqrt(n);
    ll tot=n/tmp;
    if(n%tmp)
        tot++;
    for(ll i=1; i<=n; i++)
    {
        belong[i]=(i-1)/tmp+1ll;
    }
    for(ll  i=1; i<=tot; i++)
    {
        l[i]=(i-1)*tmp+1ll;
        r[i]=i*tmp;
    }
    r[tot]=n;
}
void down(int pos)
{
    for(int i=l[pos]; i<=r[pos]; i++)
    {
        a[i]=(a[i]*mul[pos]+add[pos]+mod)%mod;
    }
    mul[pos]=1;
    add[pos]=0;
}
void update1(ll st,ll ed,ll val)
{
    if(belong[st]==belong[ed])
    {
        down(belong[st]);
        for(ll i=st; i<=ed; i++)
            a[i]+=val,a[i]%=mod;
        return ;
    }
    down(belong[st]);
    for(ll i=st; i<=r[belong[st]]; i++)
        a[i]+=val,a[i]%=mod;
    down(belong[ed]);
    for(ll  i=l[belong[ed]]; i<=ed; i++)
        a[i]+=val,a[i]%=mod;
    for(ll i=belong[st]+1; i<belong[ed]; i++)
        add[i]+=val,add[i]%=mod;
}
void update2(ll st,ll ed,ll val)
{
    if(belong[st]==belong[ed])
    {
        down(belong[st]);
        for(ll i=st; i<=ed; i++)
            a[i]*=val,a[i]=a[i]%mod;
        return ;
    }
    down(belong[st]);
    for(ll i=st; i<=r[belong[st]]; i++)
        a[i]*=val,a[i]%=mod;
    down(belong[ed]);
    for(ll  i=l[belong[ed]]; i<=ed; i++)
        a[i]*=val,a[i]%=mod;
    for(ll i=belong[st]+1; i<belong[ed]; i++)
        mul[i]*=val,add[i]*=val,mul[i]%=mod,add[i]%=mod;
}
ll ask(ll pos)
{
    return (a[pos]*mul[belong[pos]]%mod+add[belong[pos]])%mod;
}
int main()
{
    memset(add,0,sizeof(add));
    for(int i=0; i<maxn; i++)
        mul[i]=1;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i]);
    }
    buildblock();
    ll op,st,ed;
    ll val;
    while(n--)
    {
        scanf("%lld %lld %lld %lld",&op,&st,&ed,&val);
        if(op==0)
        {
            update1(st,ed,val);
        }
        else if(op==1)
        {
            update2(st,ed,val);
        }
        else if(op==2)
        {
            printf("%lld\n",ask(ed)%mod);
        }
    }
    return 0;
}

 

2019: #6284. 数列分块入门 8

题目描述

给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间询问等于一个数 ccc 的元素,并将这个区间的所有元素改为 ccc。

输入

第一行输入一个数字 nnn。

第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。

接下来输入 nnn 行询问,每行输入三个数字 lll、rrr、ccc,以空格隔开。

表示先查询位于 [l,r][l,r][l,r] 的数字有多少个是 ccc,再把位于 [l,r][l,r][l,r] 的数字都改为 ccc。

输出

对于每次询问,输出一行一个数字表示答案。

样例输入 

4
1 2 2 4
1 3 1
1 4 4
1 2 2
1 4 2

样例输出 

1
1
0
2

提示

对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1ans≤231−1。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

#define inf 0x7f7f7f7f
#define maxn 100050
#define N 100100
#define P 2

typedef long long ll;
typedef struct {
   int u, v, next, w;
} Edge;
Edge e[2];
int cnt, head[1];

inline void add1(int u, int v, int w) {
   e[cnt].u = u;
   e[cnt].v = v;
   e[cnt].w = w;
   // e[cnt].f=f;
   e[cnt].next = head[u];
   head[u] = cnt++;
   e[cnt].u = v;
   e[cnt].v = u;
   e[cnt].w = w;
   //    e[cnt].f=-f;
   e[cnt].next = head[v];
   head[v] = cnt++;
}

inline void write(int x) {
   if (x < 0)
       putchar('-'), x = -x;
   if (x > 9)
       write(x / 10);
   putchar(x % 10 + '0');
}

inline int read() {
   int x = 0, f = 1;
   char c = getchar();
   while (c < '0' || c > '9') {
       if (c == '-')
           f = -1;
       c = getchar();
   }
   while (c >= '0' && c <= '9') {
       x = x * 10 + c - '0';
       c = getchar();
   }
   return x * f;
}

int opt, l, r, c, sz, n, pos[maxn];
int a[maxn], mark[maxn];
// vector<ll>vec[505];
inline void judge(int t) {
   mark[t] = 0;
   for (int i = t * sz + 1; t <= min(n, (t + 1) * sz) - 1; i++)
       if (a[i] != a[i + 1]) {
           mark[t] = 1;
           break;
       }
}

int query(int l, int r, int val) {
   int res = 0, pl = pos[l], pr = pos[r];
   if (mark[pl]) {
       for (int i = pl * sz + 1; i <= min(n, (pl + 1) * sz); i++) a[i] = mark[pl];
       if (val != mark[pl])
           mark[pl] = 0;
   }
   for (int i = l; i <= min(r, (pl + 1) * sz); i++)
       if (a[i] == val)
           res++;
       else
           a[i] = val;
   if (pl != pr) {
       if (mark[pr]) {
           for (int i = pr * sz + 1; i <= min(n, (pr + 1) * sz); i++) a[i] = mark[pr];
           if (val != mark[pr])
               mark[pr] = 0;
       }
       for (int i = pr * sz + 1; i <= r; i++) {
           if (a[i] == val)
               res++;
           else
               a[i] = val;
       }
   }
   for (int i = pl + 1; i < pr; i++) {
       if (mark[i]) {
           if (mark[i] == val)
               res += sz;
           else
               mark[i] = val;
       } else {
           for (int j = i * sz + 1; j <= (i + 1) * sz; j++) {
               if (a[j] == val)
                   res++;
               else
                   a[j] = val;
           }
           mark[i] = val;
       }
   }
   return res;
}
int main() {
   cin >> n;
   sz = sqrt(n);
   for (int i = 1; i <= n; i++) {
       a[i] = read();
       pos[i] = (i - 1) / sz;
   }
   for (int i = 1; i <= n; i++) {
       l = read(), r = read(), c = read();
       printf("%d\n", query(l, r, c));
   }
   return 0;
}

 

2020: #6285. 数列分块入门 9

题目描述

给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及询问区间的最小众数。

输入

第一行输入一个数字 nnn。

第二行输入 nnn 个数字,第 i 个数字为 aia_iai,以空格隔开。

接下来输入 nnn 行询问,每行输入两个数字 lll、rrr,以空格隔开。

表示查询位于 [l,r][l,r][l,r] 的数字的众数。

输出

对于每次询问,输出一行一个数字表示答案。

样例输入 

4
1 2 2 4
1 2
1 4
2 4
3 4

样例输出 

1
2
2
2

提示

对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1≤n≤100000,−231≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1ans≤231−1。

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn],MAX[2020][2020],id,n,block;
int pos[maxn],val[maxn],num[maxn];//pos记录在哪个块,val[i]记录编号为i的原值,num用来求众数 
map<int,int >mp;
vector<int>v[maxn];//储存编号相同,即数相同时的原来的第几个值。用来二分求众数用 
bool visit[maxn];//标记 

void init(int x)//预处理每块之间的众数 
{
    int count=0,max1=0;
    memset(num,0,sizeof(num));
    for(int i=(x-1)*block+1;i<=n;i++)
    {
        num[a[i]]++;
        if(num[a[i]]>count||num[a[i]]==count&&val[a[i]]<val[max1])//找最小众数
        {
            count=num[a[i]];
            max1=a[i];
        }
        MAX[x][pos[i]]=max1;
    }    
} 

int er(int x,int l,int r)//二分查找块内,编号为x的数量
{
    return upper_bound(v[x].begin(),v[x].end(),r)-lower_bound(v[x].begin(),v[x].end(),l);
}

int solve(int l,int r)
{
    int ans=MAX[pos[l]+1][pos[r]-1],count=0;//中间一整块的众数 
    memset(visit,0,sizeof(visit));
    count=er(ans,l,r); 
    visit[ans]=1;
    for(int i=l;i<=min(pos[l]*block,r);i++)//暴力左边不完整块中每个数是否可能为众数
    {
        if(visit[a[i]]==0)
        {
            visit[a[i]]=1;
            int count1=er(a[i],l,r);
            if(count1>count||count1==count&&val[a[i]]<val[ans])
            {
                count=count1;
                ans=a[i];
            }
        }
    }
    if(pos[l]!=pos[r])//暴力右边不完整块中每个数是否可能为众数 
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)
        {
            if(visit[a[i]]==0)
            {
                visit[a[i]]=1;
                int count1=er(a[i],l,r);
                if(count1>count||count1==count&&val[a[i]]<val[ans])
                {
                    count=count1;
                    ans=a[i];
                }
            }
        }
    }
    return val[ans];
}
int main()
{
    scanf("%d",&n);
    block=80;
    id=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[i]=(i-1)/block+1;
        if(mp[a[i]]==0)
        {
            mp[a[i]]=++id;//id第几个出现的数
            val[id]=a[i];//保存原始值
        }
        a[i]=mp[a[i]];//保存编号(第几个出现的数)
        v[a[i]].push_back(i);
    }
    for(int i=1;i<=pos[n];i++)
        init(i);
    int l,r;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&l,&r);
        printf("%d\n",solve(l,r));
    }
    return 0;
}

 

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值