CF1540D Inverse Inversions

CF1540D Inverse Inversions

给定正整数 \(n\) 和一个整数序列 \(b_1,...,b_n\),初始值由输入给定。你需要支持下面两种操作共计 \(q\) 次:
\(1.\)修改:给定整数 \(i,x\),令 \(b_i\gets x\)
\(2.\)查询:给定正整数 \(i\)。设有 \(1\sim n\) 的排列 \(p_1,...,p_n\),满足对每个 \(1\leq k\leq n\),恰有 \(b_k\)\(j\) 满足 \(1\leq j < k\)\(p_j > p_k\)。你需要输出 \(p_i\) 的值。如有多解,输出任意一组解均可。
对于全部数据,\(1\leq n,q\leq 10^5\)\(1\leq i\leq n\),保证任意时刻均有 \(0\leq b_i < i\)(从而问题肯定有解)。

你先浅浅地想一想没有修改操作怎么做?

Idea#1

你一定可以想到(我只想到了)怎么求出排列 \(p\)。从后向前扫一遍,设排列中所有元素的集合为 \(U\)。你发现 \(p_n=b_n+1\),然后将 \(p_n\)\(U\) 中删除,进一步你发现这样的操作是可以继续进行下去的。即每次找到还没有选择的元素(也就是当前的集合 \(U\))中排名为 \(b_i+1\) 的元素 \(x\),然后令 \(p_i=x\) 即可,这样做是容易的。当然根据题目的定义,\(b_i\)\(i\) 之前 \(p_j>p_i\)\(j\) 的个数,因此得到的排列 \(p\) 是反的,最后将其赋值为 \(n-p_i\) 即可。

你幻想着把这样的操作搬到询问上去,最后无疾而终,放弃了思考。然后梦醒了,你看着昨日的自己叹息。修改操作只针对一个 \(i\),询问操作也只要求出一个 \(i\)\(p_i\),但是年少的你却思考着如何求出整个排列,一切都成了徒劳。

Idea#2

首先令 \(now=b[i]\),然后考虑通过增量调整法得到真实的 \(now\),从 \(i\) 扫到 \(n\),你会发现如果出现 b[j]>=now,则 now++,这样就可以得到真正的 \(p_i=now\) 了。

然后你发现这个做法做法可以支持多次修改,单次询问,考虑如何将其优化使之可以支持多次询问。

Optimization

\(\texttt{polylog}\) 的数据结构不太好想,看了眼数据范围,你想到了根号数据结构,序列分块,希望可以把时间复杂度平衡至 \(O(n\sqrt{n})\) 左右。
设每个块长度为 \(B\)。首先考虑把 Idea #2 中的 now++ 变成 b[i]--,这样就可以不用关注 \(now\) 的影响了。考虑预处理出所有的 \(x\) 的增量。你会发现增量至多只有 \(B\) 种,然后对于在一段区间中的 \(x\) 的增量一定是相等的。那么设上次找到的区间右端点为 \(pre\),考虑每次找到当前块中最小的 \(b_i\),记为 \(now\),位置记为 \(pos\)。那么 \([pre,now+1]\) 都可以获得相等的增量,所以 \(now\) 就是一条分界线,然后将 \([pos+1,R[bel[pos]]]\) 整体 \(-1\)

点击查看代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1000010
#define M 505
const int INF=1e9;
int n,m,B,a[N],b[M];
int bel[N],len[M],L[M],R[M];
int d[M][M];
struct NodeA
{
	int minv,pos,tag;
};

struct NodeB
{
	NodeA Tree[M<<2];
	#define lc (i<<1)
	#define rc (i<<1|1)
	
	void Pushup (int i)
	{
		if (Tree[lc].minv<Tree[rc].minv)
		{
			Tree[i].minv=Tree[lc].minv;
			Tree[i].pos=Tree[lc].pos;
		}
		else
		{
			Tree[i].minv=Tree[rc].minv;
			Tree[i].pos=Tree[rc].pos;
		}
	}
	
	void Build (int i,int l,int r)
	{
		Tree[i].minv=Tree[i].pos=Tree[i].tag=0;
		if (l==r)
		{
			Tree[i].minv=b[l],Tree[i].pos=l;
			return;
		}
		int mid=(l+r)>>1;
		Build (lc,l,mid);
		Build (rc,mid+1,r);
		Pushup (i);
	}
	
	void Cover (int i,int val)
	{
		Tree[i].minv+=val;
		Tree[i].tag+=val;
	}
	
	void Pushdown (int i)
	{
		if (Tree[i].tag)
		{
			Cover (lc,Tree[i].tag);
			Cover (rc,Tree[i].tag);
			Tree[i].tag=0;
		}
	}
	
	void Clear (int i,int l,int r,int p)
	{
		if (l==r)
		{
			Tree[i].minv=INF;
			return;
		}
		int mid=(l+r)>>1;
		Pushdown (i);
		if (p<=mid) Clear (lc,l,mid,p);
		else Clear (rc,mid+1,r,p);
		Pushup (i);
	}
	
	void Modify (int i,int l,int r,int x,int y,int val)
	{
		if (x<=l && r<=y)
		{
			Cover (i,val);
			return;
		}
		int mid=(l+r)>>1;
		Pushdown (i);
		if (x<=mid) Modify (lc,l,mid,x,y,val);
		if (mid<y) Modify (rc,mid+1,r,x,y,val);
		Pushup (i);
	}
	
}SGT;

int read ()
{
	int k=1,s=0;char ch=getchar ();
	while (!isdigit (ch)) {if (ch=='-') k=-1;ch=getchar ();}
	while (isdigit (ch)) {s=s*10+ch-'0';ch=getchar ();}
	return k*s;
}

void Update (int p,int l,int r)
{
	for (int i=l;i<=r;i++)
		b[i-l+1]=a[i];
	SGT.Build (1,1,len[p]);
	for (int i=1;i<=len[p];i++)
	{
		d[p][i]=max (d[p][i-1],SGT.Tree[1].minv);
		int q=SGT.Tree[1].pos;
		if (q<len[p]) SGT.Modify (1,1,len[p],q+1,len[p],-1);
		SGT.Clear (1,1,len[p],q);  
	}
	d[p][len[p]+1]=INF;
}

void Init ()
{
	n=read ();
	B=sqrt (n);
	for (int i=1;i<=n;i++)
	{
		a[i]=read ();
		bel[i]=(i-1)/B+1;
	}
}

void Work ()
{
	for (int i=1;i<=n;i++)
	{
		if (!L[bel[i]]) L[bel[i]]=i;
		R[bel[i]]=i; 
	}
	for (int i=1;i<=bel[n];i++)
	{
		len[i]=R[i]-L[i]+1;
		Update (i,L[i],R[i]);
	}
	m=read ();
	while (m--)
	{
		int op=read (),x=read ();
		if (op==1)
		{
			a[x]=read ();
			Update (bel[x],L[bel[x]],R[bel[x]]);
		}
		else
		{
			int ans=a[x];
			for (int i=x+1;i<=R[bel[x]];i++)
				ans+=(ans>=a[i]);
			for (int i=bel[x]+1;i<=bel[n];i++)
				ans+=upper_bound (d[i]+1,d[i]+2+len[i],ans)-d[i]-1;
			printf ("%d\n",n-ans);
		}
	}
}

signed main ()
{
	Init ();
	Work ();
	return 0; 
}
posted @ 2023-12-20 07:30  Cyber_Punk  阅读(26)  评论(0)    收藏  举报