Bzoj4241:历史研究:莫队算法

题目链接:4241:历史研究

最近考莫队怎么考怎么挂……对莫队产生了一种莫名的感觉QAQ

于是我看见什么都觉得是莫队……

这是病得治……

比如说这道题,上来先写了一发莫队套线段树,时间复杂度直接T了……

放在这里当个板子吧,谁愿意看就看,愿意拖走就拖走,但是别交,我的线段树常数大极限数据21S……

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=101000;
struct seg{
	int l,r;
	LL mx,sum,num;
	seg *lc,*rc;
	seg():mx(0),sum(0),num(0){}
};
seg *root=new seg();
int n,m,N=0,pos[maxn],cnt=0;
struct ques{int l,r,id,p;}q[maxn];
struct point{int v,id;}b[maxn];
LL ans[maxn],a[maxn];

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

bool cmp(const ques &a,const ques &b){
	return (a.p<b.p||(a.p==b.p&&a.r<b.r));
}

void build(seg *p,int l,int r){
	p->l=l; p->r=r;
	if (l+1==r){
		p->sum=0; p->num=a[l];
		p->mx=0; p->lc=p->rc=NULL;
		return;
	}else if (l+1<r){
		int mid=(l+r)>>1;
		p->lc=new seg();
		p->rc=new seg();
		if (l<mid) build(p->lc,l,mid);
		if (mid<r) build(p->rc,mid,r);
	}
}

void push_up(seg *p){
	if (p->l+1==p->r) return; p->mx=-1;
	if (p->lc) p->mx=p->lc->mx;
	if (p->rc) p->mx=max(p->mx,p->rc->mx);
}

void update(seg *p,int l,int r,int v){
	if (l<=p->l&&p->r<=r){
		p->sum+=v; p->mx=p->sum*p->num;
		return;
	}else{
		int mid=(p->l+p->r)>>1;
		if (l<mid&&p->lc) update(p->lc,l,r,v);
		if (mid<r&&p->rc) update(p->rc,l,r,v);
		push_up(p);
	}
}

bool cmpb(const point &a,const point &b){
	return a.v<b.v;
}

bool cmpid(const point &a,const point &b){
	return a.id<b.id;
}

int main(){
	scanf("%d%d",&n,&m); int blo=(int)sqrt(n);
	for (int i=1;i<=n;++i)
		b[i].v=read(),b[i].id=i;
	sort(b+1,b+n+1,cmpb);
	for (int i=1;i<=n;++i) {
		if (b[i].v!=b[i-1].v) cnt++;
		pos[b[i].id]=cnt; a[cnt]=b[i].v;
	}
	sort(b+1,b+n+1,cmpid);
	build(root,1,cnt+1);
	for (int i=1;i<=m;++i){
		q[i].l=read(); q[i].r=read();
		q[i].id=i; q[i].p=(q[i].l-1)/blo+1;
	}
	sort(q+1,q+m+1,cmp);
	int l=q[1].l,r=q[1].l-1;
	for (int i=1;i<=m;++i){
		while (l>q[i].l) l--,update(root,pos[b[l].id],pos[b[l].id]+1,1);
		while (r<q[i].r) r++,update(root,pos[b[r].id],pos[b[r].id]+1,1);
		while (l<q[i].l) update(root,pos[b[l].id],pos[b[l].id]+1,-1),l++;
		while (r>q[i].r) update(root,pos[b[r].id],pos[b[r].id]+1,-1),r--;
		ans[q[i].id]=root->mx;
	}
	for (int i=1;i<=m;++i) printf("%lld\n",ans[i]);
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值