题解:P8543 「Wdoi-2」纯粹的复仇女神

题目传送门

好题啊,不过第一发忘记了值可能相同。

思路

我们先对于每个颜色单独看,由于我们要最大值,所以我们其实只需要知道哪个最大的值能造成贡献即可。

显然,一个在询问区间里的位置 \(i\) 不能造成贡献当且仅当有一个颜色相同且值小于 \(a_i\) 的点也在垓询问区间里面,这启发我们把每种颜色的数提出来,然后对于其中的每个点找左边和右边第一个小于它的点,记为 \(L_i\)\(R_i\),没有的话,\(L_i = 0,R_i = n+1\)

每次本质上就在求 \(L_i < l \le i \le r < R_i\) 中最大的 \(a_i\),考虑扫描线。

我们可以满足 \(i \le r < R_i\),在 \(i\) 处加入 \(i\)\(R_i\) 处删掉 \(i\) 即可,所以还剩下的限制就是 \(L_i < l \le i\),我们考虑区间加一个数,然后直接单调查询即可,由于要支持加入和删除,我们开一颗线段树,并对于每个点开两个优先队列(双堆可支持加删),考虑标记永久化,每次区间加最多 \(log\) 个区间,单点查一边递归一边与该区间集合取最大值,复杂度 \(\operatorname{O}\left(n\log^2n + q\log{n}\right)\) 可以通过。

code

#include<bits/stdc++.h>
#define int long long
#define ls (p<<1)
#define rs ((p<<1)+1)
#define mid ((c[p].l+c[p].r)>>1)
using namespace std;
#define getchar() (p1 == p2 && (p2 = (p1 = buf1) + fread(buf1, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf1[1 << 23], *p1 = buf1, *p2 = buf1, ubuf[1 << 23], *u = ubuf;
namespace IO
{
	template<typename T>
	void read(T &_x){_x=0;int _f=1;char ch=getchar();while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();_x*=_f;}
	template<typename T,typename... Args>
	void read(T &_x,Args&...others){Read(_x);Read(others...);}
	const int BUF=20000000;char buf[BUF],to,stk[32];int plen;
	#define pc(x) buf[plen++]=x
	#define flush(); fwrite(buf,1,plen,stdout),plen=0;
	template<typename T>inline void print(T x){if(!x){pc(48);return;}if(x<0) x=-x,pc('-');for(;x;x/=10) stk[++to]=48+x%10;while(to) pc(stk[to--]);}
}
using namespace IO;
const int N = 2e5+10,M = 1e6+10;
int n,q,a[N],b[N],L[N],R[N],cnt,T[N],o,o1,x,y,l,mx,id,ans[M];
vector<int>v[N],v1[N];//解决左右端点问题,v1是删除位置 
//a是颜色,b是值 
struct w
{
	int l,r;
	priority_queue<int>p,p1;
}c[N<<2];
struct w1
{
	int l,r,id;
}Q[M];
void build(int p,int l,int r)
{
	c[p].l = l,c[p].r = r,c[p].p.push(0);
	if(l == r) return;
	build(ls,l,mid),build(rs,mid+1,r);
}
void change(int p,int l,int r,int k)
{
	if(l <= c[p].l && c[p].r <= r)
	{
		if(id == 0) c[p].p.push(k);
		else c[p].p1.push(k);
		return;
	}
	if(l <= mid) change(ls,l,r,k); 
	if(mid < r) change(rs,l,r,k); 
}
inline void query(int p,int l)
{
	while(!c[p].p.empty() && !c[p].p1.empty() && c[p].p.top() == c[p].p1.top()) c[p].p.pop(),c[p].p1.pop();
	mx = max(mx,c[p].p.top());
	if(l == c[p].l && c[p].r == l) return;
	if(l <= mid) query(ls,l);
	else query(rs,l);
}
inline bool cmp(w1 x,w1 y){return x.r < y.r;}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(n),read(q);
	for(int i = 1;i <= n;i++) read(a[i]),v[a[i]].push_back(i);
	for(int i = 1;i <= n;i++) read(b[i]);
	for(int i = 1;i <= n;i++)
	{
		cnt = 0;
		for(int j = 0;j < v[i].size();j++)
		{
			o = v[i][j];
			while(cnt && b[T[cnt]] >= b[o]) cnt--;
			L[o] = T[cnt],T[++cnt] = o;
		}
		cnt = 0;
		for(int j = v[i].size()-1;j >= 0;j--)
		{
			o = v[i][j];
			while(cnt && b[T[cnt]] >= b[o]) cnt--;
			R[o] = T[cnt],T[++cnt] = o;
			if(R[o] == 0) R[o] = n+1;
		}
	}
	for(int i = 1;i <= q;i++) read(Q[i].l),read(Q[i].r),Q[i].id = i;
	sort(Q+1,Q+1+q,cmp); build(1,1,n); l = 1;
	for(int i = 1;i <= n;i++) v1[R[i]].push_back(i);
	for(int i = 1;i <= n;i++)
	{ id = 1;
		for(int j = 0;j < v1[i].size();j++)
			o = v1[i][j],change(1,L[o]+1,o,b[o]);
		id = 0; change(1,L[i]+1,i,b[i]);
		while(l <= q && Q[l].r == i)
		{
			mx = 0; query(1,Q[l].l);
			ans[Q[l].id] = mx,l++;
		}
	}
	for(int i = 1;i <= q;i++) print(ans[i]),pc('\n');
	flush();
	return 0;
}
posted @ 2025-06-15 19:12  kkxacj  阅读(6)  评论(0)    收藏  举报