线段树专题

Posted iamiron-man

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树专题相关的知识,希望对你有一定的参考价值。

线段树专题

https://blog.csdn.net/qq_25605637/article/details/46967529

D-逆序对

D - Minimum Inversion Number

思路

找到第i个数前面有多少比它大的,用vis[x+1]……vis[n-1]求和,从前往后读,出现过vis就赋为1,求和用线段树。注意数字是从0到n-1的,线段树边界也为这个,但是root还是1。线段树初始化时候不能从0到n-1赋值为0,因为结点数是n的4倍,所以需要用build初始化。求出原始有多少逆序对后,因为是0..n-1的序列,所以从前往后跑的时候移动每个数能使逆序对减少0..x[i]-1的,增加n-1-x[i]个,每次累计减,取移动完后的逆序对数的最小值。

C++(AC)

#include<iostream>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath> 
#include<map> 
#define ll long long
#define pii pair<int,int>
#define mpr make_pair
#define inf 0x3f3f3f3f 
#define INF 0x3f3f3f3f3f3f3f3f
#define clr(x) memset(x,0,sizeof x)
#define rep2(i, x) for(register int i = h[x]; i; i = e[i].nxt)
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define rrep(i,x,y) if((x)>=(y))for(register int i=(x);i>=(y);i--)
#define endl "
" 
#define TT() int t;cin>>t;while(t--) 
#define PI acos(-1)
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int mod=1e9+7;
using namespace std;
const int maxn=50010;
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)
{
	sum[rt]=0;
	if (l==r) 
	{
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
}
void update(int p,int add,int l,int r,int rt)
{
	if (l==r)
	{
		sum[rt]+=add;
		return;
	}
	int m=(l+r)>>1;
	if (p<=m) 
		update(p,add,lson);
	else
		update(p,add,rson);
	PushUP(rt);
}
int query(int L,int R,int l,int r,int rt)
{
	if (L<=l && r<=R)
	  return sum[rt];
	int m=(l+r)>>1;
	int ret=0;
	if (L<=m)
	  ret+=query(L,R,lson);
	if (R>m)
	  ret+=query(L,R,rson);
	return ret;
}
int main(){
	std::ios::sync_with_stdio(true),cin.tie(0),cout.tie(0);
	int t,n,l[5010],x[5010],ans=0,Min;
	while (cin>>n) 
	{
	ans=0;
	build(0,n-1,1);
	rep(i,1,n)
	{
	  cin>>x[i];
	  update(x[i],1,0,n-1,1);
	  ans+=query(x[i]+1,n-1,0,n-1,1);
    }
    Min=ans;
    rep(i,1,n)
    {
    	ans+=n-2*x[i]-1;
    	Min=min(Min,ans);
    }
    cout<<Min<<endl;
    }
    return 0;
}

E-延迟更新

E - Knight Tournament

思路

反向线段覆盖。全新方法:正向做需要判断是否和前面冲突的时候,可以直接反着做,将前面的情况覆盖掉。本题反向进行骑士对战的胜者覆盖。然后用线段树进行区间修改,改了区间累加的代码,将所有的相加、比较之类的全部变成直接赋值覆盖。最后要注意update那里不能R<L,所以需要判断是不是胜利的骑士在两头。

C++(AC)

#include<iostream>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath> 
#include<map> 
#define ll long long
#define pii pair<int,int>
#define mpr make_pair
#define inf 0x3f3f3f3f 
#define INF 0x3f3f3f3f3f3f3f3f
#define clr(x) memset(x,0,sizeof x)
#define rep2(i, x) for(register int i = h[x]; i; i = e[i].nxt)
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define rrep(i,x,y) if((x)>=(y))for(register int i=(x);i>=(y);i--)
#define endl "
" 
#define TT() int t;cin>>t;while(t--) 
#define PI acos(-1)
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int mod=1e9+7;
using namespace std;
const int maxn=300010;
int Min[maxn<<2],add[maxn<<2];
struct data{
	int l,r,x;
}a[maxn];
void PushDown(int rt) {
         if (add[rt]) {
                 add[rt<<1] = add[rt];
                 add[rt<<1|1] = add[rt];
                 Min[rt<<1] = add[rt];
                 Min[rt<<1|1] = add[rt];
                 add[rt] = 0;
         }
}
void PushUP(int rt)
{
	Min[rt]=Min[rt<<1];
}
void build(int l,int r,int rt)
{
	add[rt] = 0;
	Min[rt]=0;
	if (l==r) 
	{
		return ;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
}
int query(int L,int R,int l,int r,int rt)
{
	if (L<=l && r<=R)
	  return Min[rt];
	PushDown(rt);
	int m=(l+r)>>1;
	int ret=0;
	if (L<=m)
	  ret=query(L,R,lson);
	if (R>m)
	  ret=query(L,R,rson);
	return ret;
}
void update(int L,int R,int c,int l,int r,int rt)
{
	    if (L <= l && r <= R) {
                 add[rt] = c;
                 Min[rt] = c;
                 return ;
         }
         PushDown(rt);
         int m = (l + r) >> 1;
         if (L <= m) update(L , R , c , lson);
         if (m < R) update(L , R , c , rson);
         PushUP(rt);
}
int main(){
	int n,m;
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	build(1,n,1);
	rep(i,1,m)
	{
		cin>>a[i].l>>a[i].r>>a[i].x;
	}
	rrep(i,m,1)
	{
		if (a[i].l<a[i].x)
		  update(a[i].l,a[i].x-1,a[i].x,1,n,1);
		if (a[i].r>a[i].x)
		  update(a[i].x+1,a[i].r,a[i].x,1,n,1);
	}
	rep(i,1,n)
	{
		cout<<query(i,i,1,n,1)<<‘ ‘;
	}
	return 0;
}

以上是关于线段树专题的主要内容,如果未能解决你的问题,请参考以下文章

线段树专题

线段树专题

非递归线段树专题

线段树专题 POJ3468 A Simple Problem with Integers

线段树专题—HDU1698 Just a Hook

线段树专题(不定期更新)