分块小记

1.数列分块1

题目描述

输入

第一行输入一个数字 。
第二行输入n个数字,第i个数字为ai,以空格隔开。
接下来输入n行询问,每行输入四个数字opt 、l、r、c,以空格隔开。
若 opt=1表示将位于l-r 的之间的数字都加c 。
若 opt=0表示询问l-r的值。

输出

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

题目分析

本题是一道板子题。涉及区间加法和单点查询。
所以:暴力必TLE。由此用分块可以解决这个问题
PS :分块过程中可能会遇到l~r距离小于block的情况

CODE:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int wadd[10100],A[500010],ans[500010],t,cnt=0;
int QRead(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int void1(){
	int l=QRead(),r=QRead(),c=QRead();
	int l1,r1;
	if(l%t==0){l1=(l/t)+1;}else l1=(l/t)+2;
	if(r%t==0){r1=(r/t)-1;}else r1=r/t;
	if(r-l>t){
		for(int i=l1;i<=r1;++i)
			wadd[i]+=c;
		int r2=(l1-1)*t;int l2=r1*t+1;
		for(int i=l;i<=r2;++i)
			A[i]+=c;
		for(int i=l2;i<=r;++i)
			A[i]+=c; 
	}
	else {
		for(int i=l;i<=r;++i){
			A[i]+=c;
		}
	}
	return 0;
}
int void2(){
	int l=QRead(),r=QRead(),c=QRead();
	if(r%t==0) ans[++cnt]=A[r]+wadd[r/t];
	else	ans[++cnt]=A[r]+wadd[(r/t)+1];
	return 0;
}
int main(){
	int n=QRead();
	t=sqrt(n);
	for(int i=1;i<=n;++i)
		A[i]=QRead();
	for(int i=1;i<=n;++i){
		int p=QRead();
		if(p)	void2();
		else	void1();
	}
	for(int i=1;i<=cnt;++i){
			printf("%d\n",ans[i]);
	}
	return 0;
}

回顾反思

  1. /与%是两个符号
  2. 记得要删调试
  3. L L L之后是被操作的范围, R R R之前是被操作的范围
  4. L L L~ R R R之间距离可能小于每块长度

2.[国家集训队]小Z的袜子(莫队)

题目描述:

	小 Z 把这 N 只袜子从1到 N 编号,然后从编号L到R尽管小 Z 并不在意两只袜子是不是完整的一双,甚至不
在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。你的任务便是告诉小 Z,
他有多大的概率抽到两只颜色相同的袜子。当然,小 Z 希望这个概率尽量高,所以他可能会询问多个L,R以方便自
己选择。然而数据中有L=R 的情况,请特判这种情况,输出0/1。

输入&输出:

	输入文件第一行包含两个正整数N和M。N为袜子的数量,M 为小 Z 所提的询问的数量。接下来一行包含N 个正整
数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数 L, R 表示一
个询问。包含 M 行,对于每个询问在一行中输出分数 A/B 表示从该询问的区间 [L,R] 中随机抽出两只袜子颜色相
同的概率。若该概率为 0 则输出 0/1,否则输出的 A/B 必须为最简分数。

题目分析:

	由题意可知需将相同颜色的袜子统计出来,同时计算出可能发生的所有事件。由数学知识可得在长为 N 的数列中
排列组合(不分先后)共有 X=(n*n-n)/2 种情况。于是套板。

CODE:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;

ll leh,c[50050],cnt[50050],ans=0;

struct node{
	ll l,r,num,a,b;
}Qt[50050];

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

bool cmp1(node a, node b){
	return (a.r/leh)==(b.r/leh)?a.l<b.l:a.r<b.r;	
}

bool cmp2(node a,node b){
	return a.num<b.num;
}

inline void add(int x){
	ans += cnt[c[x]];
	cnt[c[x]] ++;
}

inline void dlt(int x){
	cnt[c[x]] --;
	ans -= cnt[c[x]];
}

inline ll gcd(int a,int b){
	return b?gcd(b,a%b):a;
}

int main(){
	int N=QRead(),M=QRead();
	leh = sqrt(N); 
	for(int i=1;i<=N;++i){
		c[i]=QRead();
	}
	for(int i=1;i<=M;++i){
		Qt[i].l=QRead();
		Qt[i].r=QRead();
		Qt[i].num=i;
	}
	sort(Qt+1,Qt+M+1,cmp1);
	int l1=1,r1=0;
	for(int i=1;i<=M;++i){
		int Ql=Qt[i].l,Qr=Qt[i].r;
		while(l1<Ql){dlt(l1);l1++;}
		while(l1>Ql){l1--;add(l1);}
		while(r1<Qr){r1++;add(r1);}
		while(r1>Qr){dlt(r1);r1--;}
		Qt[i].a=ans;
		Qt[i].b=(Qt[i].r-Qt[i].l)*(Qt[i].r-Qt[i].l+1)/2;
		if(!ans){Qt[i].b=1;continue;}
		int gcdi=gcd(Qt[i].a,Qt[i].b);
		Qt[i].a/=gcdi;Qt[i].b/=gcdi;
	}
	sort(Qt+1,Qt+M+1,cmp2);
	for(int i=1;i<=M;++i){
		printf("%lld/%lld\n",Qt[i].a,Qt[i].b);
	}
	return 0;
} 

反思与总结:

  1. 数据可能过大
  2. 注意三目运算符
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值