线段树专题(一)

Acmer可怜啊,根本没有休息,昨天才刚刚完成了矩阵专题,今天又要开线段树专题了。唉,等我以后月薪15K的时候,我要好好享受人生。。。。。。呃,扯远了。线段树是一个非常重要的数据结构,以前就学习过,但是没有系统的刷过难题,这次我决定将kuangbin先生的专题和NotOnlySuccess大神的专题一起刷掉。因为题目多又难,所以分成几个部分(最多三个把)。




对于线段树的话,主要是理解它的树形结构吧,推荐和树状数组一起学习。似乎树状数组就是线段树的退化,树状数组节约了差不多一半的空间,但是必须满足“加法原则”(我不清楚的,说错了别打我)。理解的话,我没有什么比较好的资料,但是模版的话,强烈推荐NotOnlySuccess大神的模版,写得非常非常好。

http://wenku.baidu.com/link?url=ELhXRZB0oauIpRQ77q00kSIt9dl1zEDCUntZzoDlSPHlvPm3V--irl2JMow4HKhbMNRp_DwFyBOmU0a4wIc7L88SUvrRfXEzOUjkqA_6_X3




第一题 HDU 1166

分析:线段树的入门模版题。求区间和+点修改

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          50000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------


int sum[maxn<<2];
void pushup(int rt){
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
	if(l==r){
		scanf("%d",&sum[rt]);
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt);
}
void update(int l,int r,int rt,int p,int add){
	if(l==r){
		sum[rt]+=add;
		return ;
	}
	int m=(l+r)>>1;
	if(p<=m)update(lson,p,add);
	else update(rson,p,add);
	pushup(rt);
}
int query(int l,int r,int rt,int L,int R){
	if(L<=l&&r<=R){
		return sum[rt];
	}
	int m=(l+r)>>1;
	int ans=0;
	if(L<=m)ans+=query(lson,L,R);
	if(R>m)ans+=query(rson,L,R);
	return ans;
}
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	int t;
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++){
		int n;
		scanf("%d",&n);
		build(1,n,1);
		printf("Case %d:\n",cas);
		char op[10];
		while(1){
			scanf("%s",op);
			if(op[0]=='E')break;
			int a,b;
			scanf("%d %d",&a,&b);
			if(op[0]=='A')update(1,n,1,a,b);
			else if(op[0]=='S')update(1,n,1,a,-b);
			else cout<<query(1,n,1,a,b)<<endl;
		}
	}
    return 0;
}




第二题 HDU 1754

分析:和前面那道题相差不大,求区间和变成求区间最大值。+点修改

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          200000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------


int maxx[maxn<<2];
void pushup(int rt){
	maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int l,int r,int rt){
	if(l==r){
		scanf("%d",&maxx[rt]);
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt);
}
void update(int l,int r,int rt,int p,int xx){
	if(l==r){
		maxx[rt]=xx;
		return ;
	}
	int m=(l+r)>>1;
	if(p<=m)update(lson,p,xx);
	else update(rson,p,xx);
	pushup(rt);
}
int query(int l,int r,int rt,int L,int R){
	if(L<=l&&r<=R){
		return maxx[rt]	;
	}
	int m=(l+r)>>1;
	int ans=0;
	if(L<=m)ans=max(ans,query(lson,L,R));
	if(R>m)ans=max(ans,query(rson,L,R));
	return ans;
}
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	int n,m;
	while(~scanf("%d %d",&n,&m)){
		build(1,n,1);
		char op[10];
		int a,b;
		while(m--){
			scanf("%s %d %d",op,&a,&b);
			if(op[0]=='Q')cout<<query(1,n,1,a,b)<<endl;
			else update(1,n,1,a,b);
		}
	}
    return 0;
}




第三题 HDU 1394

分析:这是一道比较坑的题目。这道题目的意思是,给你N个数,这N个数分别是0到N-1。数列是乱序给的,让你求出它的逆序对数。然后每次将第一个放到最后一个,一次循环,这样一共可以得到N个数列,让你求出所有数列中的最小逆序对数。

那么这道题的解题思路是先求出第一个数列的逆序对数,然后可以根据前一个数列的逆序对数和数列的第一个数循环的求出下一个数列的逆序对数。

不妨设前一个数列逆序对数为ank,数列第一个数为Ai,那么下一个逆序对数为ank - Ai +n - Ai -1,我觉得应该很好想。

然后问题来了,第一个数列的逆序对数怎么求?

这里提供两种方法:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值