社区讨论

一点疑问 关于离散化

P5906【模板】回滚莫队&不删除莫队参与者 3已保存回复 4

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
4 条
当前快照
1 份
快照标识符
@mhji7rtp
此快照首次捕获于
2025/11/04 02:59
4 个月前
此快照最后确认于
2025/11/04 02:59
4 个月前
查看原帖
C
# include <bits/stdc++.h>

using namespace std;

struct query
{
    int l;
    int r;
    int id;  // 原本的编号
    int num; // 左端点所在块编号
};

bool rule(query a,query b)
{
    if (a.num != b.num)
    {
        return a.num < b.num;
    }
    return a.r < b.r;
}

struct query q[200005];
long long arr[200005];
long long tmp[200005];
int l[200005];  // 数字 i 最左边的是 l[i]
int r[200005];  // 数字 i 最右边的是 r[i] 
int ans[200005]; 
int chk[200005];
int tmpl[200005];
int tmpr[200005];
int sta[50000005];
int tot;

int main (void)
{
    int n;
    scanf ("%d",&n);

    for (int i=1;i<=n;i++)
    {
        scanf ("%d",&arr[i]);
        tmp[i] = arr[i];
    }

    sort(tmp+1,tmp+1+n);
    for (int i=1;i<=n;i++)
    {
        arr[i] = lower_bound(tmp+1,tmp+1+n,arr[i]) - tmp;
        printf ("%d ",arr[i]);
        tmpl[i]= l[i] = INT_MAX;
    }
    int siz  = (int)sqrt(n);
	int bln = n / siz;       // 块数 

    int m;
    scanf ("%d",&m);

    for (int i=1;i<=m;i++)
    {
        scanf ("%d %d",&q[i].l,&q[i].r);
        q[i].num =  q[i].l / siz;
        q[i].id = i;
      //  printf ("\n%d:%d\n",i,q[i].num);
    }

    sort(q+1,q+m+1,rule);
    
	int ll = siz,rr = siz-1;
	int tans1=0;
	for (int i=1;i<=m;i++)
	{
	//	printf("%d %d\n",q[i].l,q[i].r);
		if (q[i].num != q[i-1].num) 
		{ // 新的区间 
			ll = (q[i].num+1)*siz;
			rr = (q[i].num+1)*siz - 1;
			for (int j=1;j<=n;j++) // 重置区间统计的状态 
			{
				l[i] = INT_MAX;
				r[i] = 0;
				chk[i] = 0; 
			}
			tans1=0;
		}
		
		int tl = q[i].l,tr = q[i].r;
		
		if (tl/siz == tr/siz)  // tl与tr在同一块中 
		{
			for (int j=tl;j<=tr;j++)  // 暴力统计 
			{
				int x = arr[j];
				r[x] = max(r[x],j);
				l[x] = min(l[x],j);
				tans1 = max(r[x]-l[x],tans1);
				sta[++tot] = x;	 // 操作入栈 
			}
			ans[q[i].id] = tans1; 
			while (tot--) //不要影响下面的操作 
			{
				l[sta[tot]] = INT_MAX;
				r[sta[tot]] = 0;
			}
		//	printf ("1:%d %d\n",tl,tr);
			tans1=0;
		}
		else
		{	
	//		printf ("2: r: %d->%d\n",rr,tr);
			while (rr < tr)  // 向右扩展 
			{
				rr++;
				int x = arr[rr];
				r[x] = max(r[x],rr);
				l[x] = min(l[x],rr);
			//	printf ("向右 数字:%d 位置:%d : l:%d r:%d\n",x,rr,l[x],r[x]);
				tans1 = max(r[x]-l[x],tans1);		
				chk[x]++;		
			}
		
			int tans2 = tans1; // 最终答案 
			
	//		printf ("l: %d->%d\n",ll,tl);
			
			while (tl < ll) // 从右端点向左扩展 
			{
				ll--;
				int x = arr[ll];
				tmpr[x] = max(tmpr[x],ll);
				tmpl[x] = min(tmpl[x],ll);
				if (!chk[x]) tans2 = max(tmpr[x] - tmpl[x],tans2);  // 右端点区间没有这个值 
				else tans2 = max(max(tmpr[x],r[x])-min(l[x],tmpl[x]),tans2);		
				sta[++tot] = x;	 // 操作入栈 
				chk[x]++;
			//	printf ("向左 数字:%d 位置: %d l,r,tmpl,tmpr : %d %d %d %d\n",x,ll,l[x],r[x],tmpl[x],tmpr[x]);
			}			
			
			while (tot--) // 回滚 撤销出栈 
			{
				tmpl[sta[tot]] = INT_MAX;
				tmpr[sta[tot]] = 0;
				chk[sta[tot]]--; 
			}
			
			ans[q[i].id] = tans2;   // 最终答案 
			
			ll = (q[i].num+1)*siz;  // 将莫队区间重置到右端点 
		}
	//	printf ("\n");
	}
	
	/*for (int i=1;i<=m;i++)
	{
		printf ("%d\n",ans[i]);
	}
*/

    return 0;
}
我这份代码中的离散化无法通过此题,使用第一篇题解的离散化可以解决,这两者有什么区别吗?

回复

4 条回复,欢迎继续交流。

正在加载回复...