线段树专题
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;
}
以上是关于线段树专题的主要内容,如果未能解决你的问题,请参考以下文章