天天看点

HDU-6703-array(两种思路(主席树+set||线段树))

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6703

题目大意:给出一个n个元素的数组A,A中所有元素都是不重复的[1,n]。

有两种操作:

1.将pos位置的元素+1e7

2.查询不属于[1,r]中的最小的>=k的值。

强制在线。

思路:当时想的是树套树,但是O(nlong^2(n))总是超时,一直想不出有什么办法优化掉一个多余的logn,到最后都没有写出来...然后听旁边的队,用主席树+set过了,学长用裸的线段树过了。orz。听完思路后感觉好简单。哎。。还是太菜了QAQ。

Solve1:静态主席树+set。

直接用静态主席树维护区间问题。set维护删除的元素。由于查询的元素只会在[1,n+1]内出现,因此我们可以把+1e7看成删除了,因为我们最多的答案只会是n+1.对于每个删除的元素,将其插入到set中,查询的时候,查询[r+1,n+1]中第一个>=k的元素,再和set中第一个>=k的元素相比较,选择最小的就好了。

明明这么简单我怎么就没想到呢QAQ。。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;

const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
// freopen(".in","r",stdin);freopen(".out","w",stdout);

struct ChairTree{
	int Rt[MAXN<<5],Lc[MAXN<<5],Rc[MAXN<<5],Siz[MAXN<<5];
	int NodeCnt; 
	
	void Build(int l,int r,int &rt){
		rt=++NodeCnt;
		if(l==r) return ;
		int mid=(l+r)>>1;
		Build(l,mid,Lc[rt]);Build(mid+1,r,Rc[rt]);
	}
	int Modify(int pos,int l,int r,int rt){
		int Nrt=++NodeCnt;
		Lc[Nrt]=Lc[rt];Rc[Nrt]=Rc[rt];Siz[Nrt]=Siz[rt]+1;
		if(l==r) return Nrt;
		int mid=(l+r)>>1;
		if(pos<=mid) Lc[Nrt]=Modify(pos,l,mid,Lc[Nrt]);
		if(pos>mid) Rc[Nrt]=Modify(pos,mid+1,r,Rc[Nrt]);
		return Nrt;
	}
	int Query(int ql,int qr,int l,int r,int k){
	//[ql,qr]中找第一个>=k
//		printf("ql=%d qr=%d l=%d r=%d k=%d\n",ql,qr,l,r,k);
		if(l==r) return l;
		int x1=Siz[Lc[qr]]-Siz[Lc[ql]],x2=Siz[Rc[qr]]-Siz[Rc[ql]];
//		printf("x1=%d x2=%d\n",x1,x2);		
		//该区间中没有可用的元素 
		//if(Siz[Rt[qr]]-Siz[Rt[ql]]==0) return INF32;
		int mid=(l+r)>>1;
		int Ans=INF32;
		//[l,mid]中可能存在一个数>=k 
		if(mid>=k&&x1) Ans=Query(Lc[ql],Lc[qr],l,mid,k);
//		printf("go l Ans=%d\n",Ans);
		if(Ans!=INF32) return Ans;
		//[mid+1,r]中必定存在一个数>=k 
		if(x2) Ans=Query(Rc[ql],Rc[qr],mid+1,r,k);
		return Ans;
	}
	void Intt(int l,int r){
		NodeCnt=0;
		Build(l,r,Rt[0]);
	}
	void Update(int pos,int l,int r,int i){
		Rt[i]=Modify(pos,l,r,Rt[i-1]);
	}
	int Ans(int ql,int qr,int l,int r,int k){
		return Query(Rt[ql-1],Rt[qr],l,r,k);
	}
};
ChairTree CT;
set<int> Set;
int A[MAXN];
int B[MAXN];
int n,m;

int main(){
	freopen("1002.in","r",stdin);//freopen("1002.out","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		Set.clear();
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i) scanf("%d",&A[i]);
		CT.Intt(1,n+1);
		for(int i=1;i<=n;++i) CT.Update(A[i],1,n+1,i);
		CT.Update(n+1,1,n+1,n+1);
		int Ans=0;
		while(m--){
			int opt;scanf("%d",&opt);
			if(opt==1){
				int t1,pos;scanf("%d",&t1);
				pos=t1^Ans;
				Set.insert(A[pos]);
			}
			else{
				int t2,t3,r,k;scanf("%d%d",&t2,&t3);
				r=t2^Ans;k=t3^Ans;
//				printf("Query:ql=%d qr=%d k=%d\n",r+1,n+1,k);
				Ans=CT.Ans(r+1,n+1,1,n+1,k);//[r+1,n+1]中第一个>=k的数 
				if(Set.size()){
					set<int>::iterator it=Set.lower_bound(k);
					if(it!=Set.end()) Ans=min(*it,Ans);
				}printf("%d\n",Ans);
			}
		}
	}
	
	
}
           

Solve2:权值线段树

将数组元素进行排序,然后根据其下标建立权值线段树,维护下标的最大值。

修改的时候,将对应的值在线段树中的下标修改为INF32就好了。

查询的时候,查询[k,n+1]区间内找到第一个下标>r的位置。注意是下标,因为不能在[1,r]中出现,所以是第一个>r的元素。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;

const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
// freopen(".in","r",stdin);freopen(".out","w",stdout);

struct SegTree{
	struct Node{
		int l,r,len;
		int id,mx;
	};
	Node Tree[MAXN<<2];
	
	void PushUp(int rt){
		Tree[rt].mx=max(Tree[rt<<1].mx,Tree[rt<<1|1].mx);
	}
	void Build(int l,int r,int rt,int A[]){
		Tree[rt].l=l;Tree[rt].r=r;Tree[rt].len=r-l+1;
		if(l==r){
			Tree[rt].id=Tree[rt].mx=A[l];
			return ;
		}int mid=(l+r)>>1;
		Build(l,mid,rt<<1,A);Build(mid+1,r,rt<<1|1,A);
		PushUp(rt);
	}
	void Update(int pos,int val,int rt){
		if(Tree[rt].l==Tree[rt].r){
			Tree[rt].id=Tree[rt].mx=val;
			return ;
		}
		if(pos<=Tree[rt<<1].r) Update(pos,val,rt<<1);
		else Update(pos,val,rt<<1|1);
		PushUp(rt);
	}
	int Query(int ql,int qr,int val,int rt){
	//在[ql,qr]内找到第一个>val的 
//		printf("ql=%d qr=%d val=%d l=%d r=%d mx=%d\n",ql,qr,val,Tree[rt].l,Tree[rt].r,Tree[rt].mx);
		if(Tree[rt].l==Tree[rt].r) return Tree[rt].l;
		int Ans=INF32;
//		printf("(rt<<1): l=%d r=%d mx=%d\n",Tree[rt<<1].l,Tree[rt<<1].r,Tree[rt<<1].mx);
		if(ql<=Tree[rt<<1].r&&val<Tree[rt<<1].mx) Ans=Query(ql,qr,val,rt<<1);
//		printf("go l Ans=%d\n",Ans);
		if(Ans!=INF32) return Ans;
//		printf("(rt<<1|1): l=%d r=%d mx=%d\n",Tree[rt<<1|1].l,Tree[rt<<1|1].r,Tree[rt<<1|1].mx);
		if(qr>=Tree[rt<<1|1].l&&val<Tree[rt<<1|1].mx) Ans=Query(ql,qr,val,rt<<1|1);
//		printf("go r Ans=%d\n",Ans);
		return Ans;
	}
	void Show(int rt){
		printf("l=%d r=%d mx=%d\n",Tree[rt].l,Tree[rt].r,Tree[rt].mx);
		if(Tree[rt].l==Tree[rt].r) return ;
		Show(rt<<1);Show(rt<<1|1);
	}
};
SegTree Seg;
PII A[MAXN];
int B[MAXN];
int n,m;

int Cmp1(PII a,PII b){
	return a.second<b.second;
}
int main(){
	//freopen("1002.in","r",stdin);//freopen("1002.out","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d",&A[i].first);
			A[i].second=i;
		}sort(A+1,A+1+n);
		for(int i=1;i<=n;++i){
			B[i]=A[i].second;
		}sort(A+1,A+1+n,Cmp1);
//		for(int i=1;i<=n;++i) printf("%d ",B[i]);printf("\n");
		B[++n]=INF32;
		Seg.Build(1,n,1,B);
		int Ans=0;
		while(m--){
			int opt;scanf("%d",&opt);
			if(opt==1){
				int t1,pos;scanf("%d",&t1); 
				pos=t1^Ans;
				Seg.Update(A[pos].first,INF32,1);
//				printf("Update:%d\n",pos);Seg.Show(1);printf("\n");
			}
			else{
				int t2,t3,r,k;scanf("%d%d",&t2,&t3);
				r=t2^Ans;k=t3^Ans;//在[k,n]区间内找第一个>r的位置 
				printf("%d\n",Ans=Seg.Query(k,n,r,1));
			}
		}
	}
}
           

继续阅读