cf 1117G Recursive Queries

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/87942287

2500分的题还是不会做,菜哭.jpg,看了网上题解,觉得十分精妙

其实f(l,r)相当于一个不断删数字然后求产生的价值和的过程,设第i个数字左边第一个比他大的数字为第lind[i]个数字,右边的为第rind[i]个,那么删掉第i个数字,留下左右两边的数字,所产生的价值就是(rind[i]-1)-(lind[i]+1)+1,也就是这一段的长度。

吧询问离线,然后分两段计算,这样就不会重复计算,导致出错

我们先计算从每个数字的lind[i]+1到第i个这一段的代价,从左到有扫一遍,扫到i,就把lind[i]+1到i全部加1,lq[i]这里有一个询问,也就是询问lq[i][j]到i的价值,由于我们从左到右,所以此时lq[i][j]到i已经全部用线段树求值出来了。

再计算从i+1到rind[i]-1这一段的价值,从右向左扫,然后加到从i到rq[i][j]这一段的询问的答案中

#include<bits/stdc++.h>
#define maxl 1000010
#define mp make_pair
#define pb push_back
using namespace std;

struct node
{
	int l,r;
	long long sum,tag;
}tree[maxl<<2];
int n,q,len,top;
int a[maxl],lind[maxl],rind[maxl],s[maxl],l[maxl],r[maxl];
typedef pair<int,int> p;
vector <p> lq[maxl],rq[maxl]; 
long long ans[maxl];

inline void prework()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	a[0]=a[n+1]=2*1e9;
	top=0;s[++top]=0;
	for(int i=1;i<=n;i++)
	{
		while(a[i]>a[s[top]] && top>0)
			top--;
		s[++top]=i;lind[i]=s[top-1];
	}
	top=0;s[++top]=n+1;
	for(int i=n;i>=1;i--)
	{
		while(a[i]>a[s[top]] && top>0)
			top--;
		s[++top]=i;rind[i]=s[top-1];
	}
	for(int i=1;i<=q;i++)
		scanf("%d",&l[i]);
	for(int i=1;i<=q;i++)
		scanf("%d",&r[i]);
	for(int i=1;i<=q;i++)
	{
		lq[r[i]].pb(mp(l[i],i));
		rq[l[i]].pb(mp(r[i],i));
	}
}

inline void build(int k,int l,int r)
{
	tree[k].l=l;tree[k].r=r;tree[k].sum=0;tree[k].tag=0;
	if(l==r)
		return;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}

inline long long query(int k,int l,int r)
{
	if(tree[k].l==l && tree[k].r==r)
		return tree[k].sum;
	int mid=(tree[k].l+tree[k].r)>>1;
	long long res=(r-l+1)*tree[k].tag;
	if(r<=mid)
		res+=query(k<<1,l,r);
	else if(l>mid)
		res+=query(k<<1|1,l,r);
	else
		res+=query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
	return res;
}

inline void add(int k,int l,int r,int val)
{
	tree[k].sum+=(r-l+1)*val;
	if(tree[k].l==l &&tree[k].r==r)
	{
		tree[k].tag+=val;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid)
		add(k<<1,l,r,val);
	else if(l>mid)
		add(k<<1|1,l,r,val);
	else
		add(k<<1,l,mid,val),add(k<<1|1,mid+1,r,val);
	//tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}

inline void mainwork()
{
	int len;
	build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		add(1,lind[i]+1,i,1);
		len=lq[i].size();
		for(int j=0;j<len;j++)
			ans[lq[i][j].second]+=query(1,lq[i][j].first,i);
	}
	build(1,1,n);
	for(int i=n;i>=1;i--)
	{
		if(i+1<=rind[i]-1)
			add(1,i+1,rind[i]-1,1);
		len=rq[i].size();
		for(int j=0;j<len;j++)
			ans[rq[i][j].second]+=query(1,i,rq[i][j].first);
	}
}

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

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/87942287
今日推荐