标签:blank uil love 两种 turn sig 二分答案 c++ 大小
有一个数组 \(a\),它是一个长度为\(n(n\le1e5)\)的全排列。
现在他想执行多次下列两种操做:
问经过 \(m(m\le1e5)\)次操作后\(a[k]\)为多少?
这个题目挺难的
直接模拟题意显然会\(TLE\)
因为我们最终只要求一个元素,考虑二分答案\(x\)
那么排列中大于等于\(x\)的数全都设为\(1\),小于\(x\)的数都设为 \(0\)
若为升序排序
现在区间排序,只要把区间里的\(0\)都移到最前面, \(1\)都移到最后面。
对于区间\([l, r]\)查询\([l, r]\)的子段和\(sum\)。
然后将\([l, r - sum]\)修改为 \(0\),\([r - sum + 1, r]\)修改为\(1\).
反之亦然
这个题目主要是考虑相对大小
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m,k;
int a[maxn];
int tree[maxn<<2],lazy[maxn<<2];
int opt[maxn],l[maxn],r[maxn];
void build(int node,int l,int r,int x){
lazy[node]=-1;
if(l==r){
tree[node]=(a[l]>=x);
return ;
}
int mid=(l+r)/2;
build(node<<1,l,mid,x);
build(node<<1|1,mid+1,r,x);
tree[node]=tree[node<<1]+tree[node<<1|1];
}
void updown(int node,int l,int r){
if(lazy[node]!=-1){
int mid=(l+r)/2;
lazy[node<<1]=lazy[node];
lazy[node<<1|1]=lazy[node];
tree[node<<1]=(mid-l+1)*lazy[node];
tree[node<<1|1]=(r-mid)*lazy[node];
lazy[node]=-1;
}
}
void update(int node,int L,int R,int l,int r,int add){
if(L<=l&&r<=R){
tree[node]=(r-l+1)*add;
lazy[node]=add;
return ;
}
updown(node,l,r);
int mid=(l+r)/2;
if(mid>=L) update(node<<1,L,R,l,mid,add);
if(mid<R) update(node<<1|1,L,R,mid+1,r,add);
tree[node]=tree[node<<1]+tree[node<<1|1];
}
int query(int node,int L,int R,int l,int r){
if(L<=l&&r<=R){
return tree[node];
}
updown(node,l,r);
int mid=(l+r)/2,sum=0;
if(mid>=L) sum+=query(node<<1,L,R,l,mid);
if(mid<R) sum+=query(node<<1|1,L,R,mid+1,r);
return sum;
}
bool check(int x){
build(1,1,n,x);
for(int i=1;i<=m;i++){
int sum=query(1,l[i],r[i],1,n);
if(opt[i]==0){
if(r[i]-sum>=l[i]) update(1,l[i],r[i]-sum,1,n,0);
if(r[i]>=r[i]-sum+1) update(1,r[i]-sum+1,r[i],1,n,1);
}else{
if(l[i]+sum-1>=l[i]) update(1,l[i],l[i]+sum-1,1,n,1);
if(r[i]>=l[i]+sum) update(1,l[i]+sum,r[i],1,n,0);
}
}
return query(1,k,k,1,n);
}
signed main(){
int _;scanf("%d",&_);
while(_--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&opt[i],&l[i],&r[i]);
}
scanf("%d",&k);
int l=1,r=n,ans=-1;
while(l<=r){
if(check(mid)){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
printf("%d\n",ans);
}
return 0;
}
HDU 5649 DZY Love Sorting 题解(二分套线段树)
标签:blank uil love 两种 turn sig 二分答案 c++ 大小
原文地址:https://www.cnblogs.com/hunxuewangzi/p/14656265.html