HDU - 5649 DZY Loves Sorting (线段树还能这样用)

https://vjudge.net/problem/HDU-5649

题意:一个n的排列,然后执行Q次操作,每次操作是对某个区间从小到大排序或者是从大到小排序。最后只查询一次,输出第k个位置当前的数。

思路:

这个题只查询了一次,所以有了特殊的解法。

我们二分答案,直接枚举最后的答案。

然后把原来的数列中 大于等于这个答案的置为一,小于这个答案的职位零,然后用线段树操作,

就成了 区间修改, 升序, 把区间的1 放后面,,降序,把区间的 1 放前面。

最后看看我们要查的那个位置,是1 的话就说明枚举的有可能大了,,反之就是小了。

 

写代码的时候,出现了错误,就是左区间的值大于右区间的值。

如果全是 0 或者全是1 的情况下,会出现左区间大于右区间。

 

#include 
#define mem(x,v) memset(x,v,sizeof(x)) 
#define go(i,a,b)  for (int i = a; i <= b; i++)
#define og(i,a,b)  for (int i = a; i >= b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
struct segtree{
	int l,r,lazy,val;
}f[N*4];
int n,m,s[N],t[N],a[N],b[N],c[N],kk;
void push_down(int now){
	if (f[now].lazy == -1) return;
	f[now*2].val = (f[now*2].r - f[now*2].l)*f[now].lazy;
	f[now*2+1].val = (f[now*2+1].r - f[now*2+1].l)*f[now].lazy;
	f[now*2].lazy = f[now].lazy;
	f[now*2+1].lazy = f[now].lazy;
	f[now].lazy = -1; 
	return;
}

void build(int now, int l, int r){
	f[now].l = l; f[now].r = r; f[now].lazy = -1;
	if (r - l == 1){
		f[now].val = t[l]; return;
	}
	int m = (l + r)/2;
	build(now*2,l,m);
	build(now*2+1,m,r);
	f[now].val = f[now*2].val + f[now*2+1].val; return;
}


void Insert(int now, int l, int r, int op){
	if (l > r) return;
	if (l <= f[now].l && r >= f[now].r - 1){
		f[now].val = (f[now].r - f[now].l) * op;
		f[now].lazy = op;
		return;
	}
	push_down(now);
	int m = (f[now].r + f[now].l) / 2;
	if (l < m) Insert(now*2,l,r,op);
	if (r >= m) Insert(now*2+1,l,r,op);
	f[now].val = f[now*2].val + f[now*2+1].val;
	return;
}

int Qurey(int now, int l, int r){
	int ans = 0;
	if (l <= f[now].l && r >= f[now].r-1){
		return f[now].val;
	}
	push_down(now);
	int m = (f[now].l + f[now].r) / 2;
	if (l < m) ans += Qurey(now*2,l,r);
	if (r >= m) ans += Qurey(now*2+1,l,r);
	return ans;
}

bool find(int mid){
	go(i,1,n) if (s[i] >= mid) t[i] = 1; else t[i] = 0; 
	build(1,1,n+1);
	go(i,1,m){
		int k = Qurey(1,b[i],c[i]);
		if (a[i] == 0)  Insert(1,b[i],c[i]-k,0),Insert(1,c[i]-k+1,c[i],1);
		if (a[i] == 1)  Insert(1,b[i],b[i]+k-1,1),Insert(1,b[i]+k,c[i],0);
	}

	return Qurey(1,kk,kk);
}
int main(){
	int T; cin>>T;
	while(T--)	{
		scanf("%d%d",&n,&m);
		go(i,1,n) scanf("%d",&s[i]);
		go(i,1,m) scanf("%d%d%d",&a[i],&b[i],&c[i]);
		scanf("%d",&kk);
		int l = 0, r = n+1,ans = -1;
		while(l <= r){
			int mid = (l + r)/2;
			if (find(mid)) {l = mid + 1; ans = mid; } else r = mid - 1;
		}
		printf("%d\n",ans);
	}
	return 0;
}

 

你可能感兴趣的:(#,线段树,树状数组)