HDU - 6315 Naive Operations(線段樹+思維)

題目鏈接:點擊查看

題目大意:給出一個數列 a 和一個數列 b ,其中數列 a 初始時全部爲 0 ,數列 b 初始時是一個 1 ~ n 的排列,接下來共有 m 次操作,每次操作分爲兩種:

  1. add l r :在區間 [ l , r ] 內的 a[ i ] 都加上 1
  2. query l r :查詢區間 [ l , r ] 內的所有 \small \frac{a[i]}{b[i]} 之和

題目分析:如果直接維護 a[ i ] / b[ i ] 的話可能不太好維護,但是我們可以反向思考,對於數列 b 維護一個線段樹,每個節點維護一個 mmin 和一個 sum,分別代表區間內的最小值以及當前區間的貢獻,這個最小值代表的是:當前區間至少還需要進行多少次 add 操作纔會產生貢獻,因爲初始時每個葉子結點的 mmin 都將其賦值爲 b[ i ] ,這樣每次執行 add 操作時,如果 mmin > 1 的話,那麼直接讓 mmin 減一即可,如果 mmin = 1 的話,說明當前區間中,存在葉子結點經過此次 add 後悔變成 0 ,也就是 a[ i ] / b[ i ] 可以多貢獻 1 了,對於所有 mmin = 1 的區間,繼續向下遞歸,直到葉子結點位置,此時將葉子結點的 mmin 重新賦值爲 b[ i ] ,並且將 sum 加一就好了

因爲是區間修改和區間查詢,所以需要加一個 lazy 標記

代碼:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

struct Node
{
	int l,r,mmin,sum,lazy;
}tree[N<<2];

int a[N];

void pushup(int k)
{
	tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);
	tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}

void pushdown(int k)
{
	if(tree[k].lazy)
	{
		int lz=tree[k].lazy;
		tree[k].lazy=0;
		tree[k<<1].lazy+=lz;
		tree[k<<1].mmin+=lz;
		tree[k<<1|1].lazy+=lz;
		tree[k<<1|1].mmin+=lz;
	}
}

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

void update(int k,int l,int r)
{
	if(tree[k].r<l||tree[k].l>r)
		return;
	if(tree[k].l>=l&&tree[k].r<=r)
	{
		if(tree[k].mmin>1)
		{
			tree[k].mmin--;
			tree[k].lazy--;
			return;
		}
		else if(tree[k].l==tree[k].r)
		{
			tree[k].mmin=a[tree[k].l];
			tree[k].sum++;
			return;
		}
	}
	pushdown(k);
	update(k<<1,l,r);
	update(k<<1|1,l,r);
	pushup(k);
}

int query(int k,int l,int r)
{
	if(tree[k].r<l||tree[k].l>r)
		return 0;
	if(tree[k].l>=l&&tree[k].r<=r)
		return tree[k].sum;
	pushdown(k);
	return query(k<<1,l,r)+query(k<<1|1,l,r);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=1;i<=n;i++)
			scanf("%d",a+i);
		build(1,1,n);
		while(m--)
		{
			char s[10];
			int l,r;
			scanf("%s%d%d",s,&l,&r);
			if(s[0]=='a')
				update(1,l,r);
			else
				printf("%d\n",query(1,l,r));
		}
	}











    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章