zoukankan      html  css  js  c++  java
  • 【BZOJ3489】A simple rmq problem kd-tree

    【BZOJ3489】A simple rmq problem

    Description

    因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

    Input

    第一行为两个整数N,MM是询问数,N是序列的长度(N<=100000M<=200000)

    第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

    再下面M行,每行两个整数xy

    询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<)

    l=min(x+lastans)mod n+1,(y+lastansmod n+1);

    r=max(x+lastans)mod n+1,(y+lastansmod n+1);

    Lastans表示上一个询问的答案,一开始lastans0

    Output

    一共M行,每行给出每个询问的答案。

    Sample Input

    10 10
    6 4 9 10 9 10 9 4 10 4
    3 8
    10 1
    3 4
    9 4
    8 1
    7 8
    2 9
    1 1
    7 3
    9 9

    Sample Output

    4
    10
    10
    0
    0
    10
    0
    4
    0
    4

    HINT

    注意出题人为了方便,input的第二行最后多了个空格。

    2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测

    题解:在[l,r]中只出现一次等价于:上一次出现的位置<l&&l<=这次出现的位置<=r&&下一次出现的位置>r。然后写个三维kd-tree就行了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define rep for(int i=0;i<3;i++)
    #define D1 ((D+1)%3)
    #define D2 ((D+2)%3)
    using namespace std;
    const int maxn=100010;
    int A,B,D,n,m,ans,root;
    int head[maxn],pre[maxn],next[maxn],buc[maxn],v[maxn];
    struct kd
    {
    	int v[3],sm[3],sn[3],ls,rs,ms,s;
    	kd (){}
    	kd (int a,int b,int c,int d){v[0]=sm[0]=sn[0]=a,v[1]=sm[1]=sn[1]=b,v[2]=sm[2]=sn[2]=c,s=ms=d,ls=rs=0;}
    	int	& operator [] (int a)	{return v[a];}
    	bool operator < (kd a)	const
    	{
    		return (v[D]==a[D])?((v[D1]==a[D1])?(v[D2]==a[D2]):(v[D1]<a[D1])):(v[D]<a[D]);
    	}
    };
    kd t[maxn];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void pushup(int x,int y)
    {
    	rep t[x].sm[i]=max(t[x].sm[i],t[y].sm[i]),t[x].sn[i]=min(t[x].sn[i],t[y].sn[i]);
    	t[x].ms=max(t[x].ms,t[y].ms);
    }
    int build(int l,int r,int d)
    {
    	if(l>r)	return 0;
    	D=d;
    	int mid=l+r>>1;
    	nth_element(t+l,t+mid,t+r+1);
    	t[mid].ls=build(l,mid-1,(d+1)%3),t[mid].rs=build(mid+1,r,(d+1)%3);
    	if(t[mid].ls)	pushup(mid,t[mid].ls);
    	if(t[mid].rs)	pushup(mid,t[mid].rs);
    	return mid;
    }
    int check(int x)
    {
    	if(t[x].ms<=ans||t[x].sm[0]<A||t[x].sn[0]>B||t[x].sn[1]>=A||t[x].sm[2]<=B)	return 0;
    	return 1;
    }
    void query(int x)
    {
    	if(!x||!check(x))	return ;
    	if(t[x][0]>=A&&t[x][0]<=B&&t[x][1]<A&&t[x][2]>B&&t[x].s>ans)	ans=t[x].s;
    	query(t[x].ls),query(t[x].rs);
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i;
    	for(i=1;i<=n;i++)
    	{
    		v[i]=rd(),pre[i]=head[v[i]];
    		if(head[v[i]])	next[head[v[i]]]=i;
    		head[v[i]]=i;
    	}
    	for(i=1;i<=n;i++)	if(!next[i])	next[i]=n+1;
    	for(i=1;i<=n;i++)	t[i]=kd(i,pre[i],next[i],v[i]);
    	root=build(1,n,0);
    	for(i=1;i<=m;i++)
    	{
    		A=(ans+rd())%n+1,B=(ans+rd())%n+1;
    		if(A>B)	swap(A,B);
    		ans=0,query(root);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    VS2013折叠代码、打开代码的快捷键
    用if做了一个简单的猜拳游戏(做的不好还请指点,谢谢!)
    一维数组的应用
    do while 与while的区别!
    作业.把c语言输出的基础差不多都概括了!
    C语言基础
    c语言:蜗牛的爬行。
    QQ群成员提取
    入门教程2
    VMware WorkStations最小化安装&配置&卸载CentOS 7
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7114730.html
Copyright © 2011-2022 走看看