#3196. color

题面:无
做法:①分块在线做法
注意 数组应该先开小维再开大维

AC毒瘤卡常

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
const int N=50010;
using namespace std;
int a[N],f[40][40],fa[N],b[N],c[40][40][N],st[40],ed[40],ans,tot;
int n,m,t,L,R;
inline void prework()
{
	t=(int)pow(n*1.0,1.0/3);
	int l=0;
	if(t) l=n/t;
	for(int i=1;i<=t;++i)st[i]=(i-1)*l+1,ed[i]=i*l;
	if(ed[t]<n){st[t+1]=ed[t]+1,ed[++t]=n;}
	memcpy(b,a,sizeof(a));
	sort(b+1,b+1+n);
	for(int i=1;i<=n;++i)if(b[i]!=b[i-1]||i==1)fa[++tot]=b[i];
	for(int i=1;i<=n;++i)a[i]=lower_bound(fa+1,fa+1+tot,a[i])-fa;
	
	for(int i=1;i<=t;++i){
		for(int j=i;j<=t;++j){
			for(int k=st[i];k<=ed[j];++k){
				c[i][j][a[k]]++;
			}
			for(int k=1;k<=tot;++k)
				f[i][j]=max(f[i][j],c[i][j][k]);
			
		}
	}
	
}
inline void update(int i){
	c[L][R][a[i]]++;
	ans=ans>c[L][R][a[i]]?ans:c[L][R][a[i]];
}

inline int solve(int x,int y){
	int l,r;
	for(int i=1;i<=t;++i)if(ed[i]>=x){l=i;break;}
	for(int i=1;i<=t;++i)if(ed[i]>=y){r=i;break;}
	if(l+1<=r-1){L=l+1,R=r-1;}else L=R=0;
	ans=f[L][R];
	if(l!=r){
		for(int i=x;i<=ed[l];++i)update(i);
		for(int i=st[r];i<=y;++i)update(i);
		for(int i=x;i<=ed[l];++i)--c[L][R][a[i]];
		for(int i=st[r];i<=y;++i)--c[L][R][a[i]];
	}else{
		for(int i=x;i<=y;++i)update(i);
		for(int i=x;i<=y;++i)--c[L][R][a[i]];
	}
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	prework();
	int l,r,k;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&l,&r,&k);
		int res=solve(l,r);
		if(res>=k)printf(">_<\n");
		else printf("QAQ\n");
	}
	return 0;
}

做法②莫队
思路同分块,但离线处理。
而且跑得比分块快。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 50005
int col[N],ask[N][3],n,q,t[N],p[N],anss[N],k,ans;
inline bool cmp(int x,int y){
	return ask[x][0]/k<ask[y][0]/k||(ask[x][0]/k==ask[y][0]/k)&&ask[x][1]<ask[y][1];
}
inline void modify(int c,int op){
	if(op==-1&&ans==t[c]&&p[t[c]]==1){
		ans--;
    }
    if(op==1&&ans==t[c])ans++;
    p[t[c]]--;
    t[c]+=op;
    p[t[c]]++;
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>q;
	k=sqrt(n);
	for(int i=1;i<=n;i++){
		cin>>col[i];
    }
    int ord[n];
    for(int i=1;i<=q;i++){
		cin>>ask[i][0]>>ask[i][1]>>ask[i][2];
		ord[i]=i;
	}
	sort(ord+1,ord+1+q,cmp);
    for(int l=1,r=0,i=1;i<=q;i++){
		int u=ask[ord[i]][0],v=ask[ord[i]][1];
		for(;l<u;l++)modify(col[l],-1);
		for(;l>u;l--)modify(col[l-1],1);
		for(;r>v;r--)modify(col[r],-1);
		for(;r<v;r++)modify(col[r+1],1);
	    anss[ord[i]]=ans;
	}
	for(int i=1;i<=q;i++){
		if(anss[i]>=ask[i][2])cout<<">_<"<<endl;
		else cout<<"QAQ"<<endl;
	}
	return 0;
}

做法③优秀暴力+预处理+分类讨论
其他做法实时更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值