codeforces1404C固定小数点の削除

https://codeforces.com/contest/1404/problem/C

私はあまりにも食べ物です、紫に戻ってリメイクしてください

重要なのは結論を見つけることです。つまり、現在の位置の前にp個の位置を削除できると仮定します。ia[i]> = pの場合、この位置も削除する必要があります。最初の1-(ia [i])を削除してください、そして現在の位置を削除し、以前に削除されていない(ia [i])-pを削除すると、iのもう1つの位置を削除できます。

次に、クエリの右端に基づいて並べ替えます。rが1ビット右にシフトされるたびに、ia [i]> = 0の場合、p ++にし、p ++を許可できない位置を検討します。各位置の現在の答えがf [ 1]、f [2] ... f [r]は、(i、r)からの答えを意味します。明らかに、f配列は増加しないため、ツリー配列を使用して、左端のf [ind] <iaを見つけます[i]の位置は、これ以降、p ++を使用できないことを意味します。indのツリー配列で+1するだけです。

接頭辞の合計は、各位置でどれだけ減算するかを示すために使用されます。ツリー配列は接頭辞の合計を維持します。最終的な答えはp-sum(l)です。つまり、1 + lでp ++が許可されない回数です。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;
const int inf=2e9;

int n,m,q,cnt,tot,cas;
int a[maxl],ans[maxl];
int b[maxl];
bool vis[maxl];
char s[maxl];
struct qu{int l,id;};
vector<qu> out[maxl];

inline void prework()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		a[i]=i-a[i];
	}
	int x,y;
	for(int i=1;i<=q;i++)	
	{
		scanf("%d%d",&x,&y);
		out[n-y].push_back(qu{1+x,i});
	}
}

inline int find(int n,int k,int p)
{
	int now=0,cnt=p;
	for(int i=log2(n);i>=0;i--)
	if(now+(1<<i)<=n)
	{
		now+=1<<i;cnt-=b[now];
		if(cnt<k)
			cnt+=b[now],now-=1<<i;
	}
	return now+1;
}

inline void add(int i,int x)
{
	while(i<=n)
	{
		b[i]+=x;
		i+=i&-i;
	}
}

inline int sum(int i)
{
	int ret=0;
	while(i)
	{
		ret+=b[i];
		i-=i&-i;
	}
	return ret;
}

inline void mainwork()
{
	int p=0,ind;
	for(int r=1;r<=n;r++)
	{
		if(a[r]>=0)
		{
			ind=find(r,a[r],p);
			++p;
			add(ind,1);
		}
		for(qu d:out[r])
			ans[d.id]=p-sum(d.l);
	}
}

inline void print()
{
	for(int i=1;i<=q;i++)
		printf("%d\n",ans[i]);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

おすすめ

転載: blog.csdn.net/liufengwei1/article/details/108456978