• 【bzoj3489】 A simple rmq problem


    http://www.lydsy.com/JudgeOnline/problem.php?id=3489 (题目链接)

    题意

      在线求区间不重复出现的最大的数。

    Solution

      KDtree竟然能够处理这种问题,好神啊。

      以下转自:http://trinklee.blog.163.com/blog/static/2381580602015422933539/

      记录每个位置的数前一次出现的位置pre[i]和后一次出现的位置nxt[i],然后我们询问的就是

      1. l<=i<=r

      2. pre[i]<l

      3. nxt[i]>r

      满足三个条件下的max(a[i])

      将每个点的信息看作三维空间上带权值的点(i,pre[i],nxt[i]),然后建立kdtree。

      询问的话,等价于第一维在[l,r]范围内,第二维在[0,l-1]范围内,第三维在[r+1,+oo]范围内的一个三维空间内,查询在里面的点权最大值。于是这样就能转换成kdtree啦~

      关于kdtree:

      1. 建树跟二维的一样建法,xyz三个坐标轮流换,并且维护当前域内的点权max

      2. 查询的时候,如果当前域内max<=ans,直接不做(剪枝1),如果当前点在查询域内则更新答案,如果子空间与查询域不交则不查(剪枝2)

    细节

      竟然1A了w(゚Д゚)w

    代码

    // bzoj3489
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #define LL long long
    #define inf 1<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010,maxm=200010;
    int a[maxn],head[maxn],pre[maxn],nxt[maxn],ax[3],ay[3];
    int D,n,m,rt;
    
    struct KDtree {
    	int l,r,val,Max,v[3],mn[3],mx[3];
    	friend bool operator < (const KDtree a,const KDtree b) {
    		return a.v[D]<b.v[D];
    	}
    }tr[maxn];
    
    void update(int k) {
    	for (int i=0;i<=2;i++) {
    		if (tr[k].l) {
    			tr[k].mx[i]=max(tr[k].mx[i],tr[tr[k].l].mx[i]);
    			tr[k].mn[i]=min(tr[k].mn[i],tr[tr[k].l].mn[i]);
    		}
    		if (tr[k].r) {
    			tr[k].mx[i]=max(tr[k].mx[i],tr[tr[k].r].mx[i]);
    			tr[k].mn[i]=min(tr[k].mn[i],tr[tr[k].r].mn[i]);
    		}
    	}
    	if (tr[k].l) tr[k].Max=max(tr[k].Max,tr[tr[k].l].Max);
    	if (tr[k].r) tr[k].Max=max(tr[k].Max,tr[tr[k].r].Max);
    }
    int build(int l,int r,int p) {
    	D=p;
    	int mid=(l+r)>>1;
    	nth_element(tr+l,tr+mid,tr+r+1);
    	if (l<mid) tr[mid].l=build(l,mid-1,(p+1)%3);
    	if (r>mid) tr[mid].r=build(mid+1,r,(p+1)%3);
    	update(mid);
    	return mid;
    }
    bool in(int x,int y,int X,int Y) {
    	return x>=X && y<=Y;
    }
    bool out(int x,int y,int X,int Y) {
    	return y<X || x>Y;
    }
    int query(int k) {
    	if (!k) return 0;
    	int flag=1,res=0;
    	for (int i=0;i<=2;i++) {
    		if (out(tr[k].mn[i],tr[k].mx[i],ax[i],ay[i])) return 0;
    		flag&=in(tr[k].mn[i],tr[k].mx[i],ax[i],ay[i]);
    	}
    	if (flag) return tr[k].Max;
    
    	flag=1;for (int i=0;i<=2;i++) flag&=in(tr[k].v[i],tr[k].v[i],ax[i],ay[i]);
    	if (flag) res=tr[k].val;
    
    	if (tr[tr[k].l].Max>tr[tr[k].r].Max) {
    		if (res<tr[tr[k].l].Max) res=max(res,query(tr[k].l));
    		if (res<tr[tr[k].r].Max) res=max(res,query(tr[k].r));
    	}
    	else {
    		if (res<tr[tr[k].r].Max) res=max(res,query(tr[k].r));
    		if (res<tr[tr[k].l].Max) res=max(res,query(tr[k].l));
    	}
    	return res;
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) {
    		scanf("%d",&a[i]);
    		int x=head[a[i]];head[a[i]]=i;
    		pre[i]=x;nxt[x]=i;
    	}
    	for (int i=1;i<=n;i++) {
    		tr[i].v[0]=tr[i].mx[0]=tr[i].mn[0]=i;
    		tr[i].v[1]=tr[i].mx[1]=tr[i].mn[1]=pre[i];
    		tr[i].v[2]=tr[i].mx[2]=tr[i].mn[2]=nxt[i] ? nxt[i] : n+1;
    		tr[i].val=tr[i].Max=a[i];
    	}
    	rt=build(1,n,0);
    	int ans=0;
    	for (int l,r,x,y,i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y);
    		l=min((x+ans)%n+1,(y+ans)%n+1);
    		r=max((x+ans)%n+1,(y+ans)%n+1);
    		ax[0]=l,ay[0]=r;
    		ax[1]=0,ay[1]=l-1;
    		ax[2]=r+1,ay[2]=n+1;
    		ans=query(rt);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JAVA语法之小结
    JAVA之经典Student问题1
    Android之动画1
    Android之屏幕测试
    Android之点击切换图片
    Android之标签选项卡
    Android简单计算器
    Javascript之相册拖动管理
    Javascript之改变盒子颜色
    CSS之照片翻转
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6262992.html
Copyright © 2020-2023  润新知