1. 程式人生 > 實用技巧 >線段樹專題

線段樹專題

線段樹專題

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 "\n" 
#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 "\n" 
#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;
}