洛谷 P4137 Rmq Problem / mex

https://www.luogu.org/problemnew/show/P4137

只会log^2的带修主席树。。

看了题解,发现有高妙的一个log做法:权值线段树上,设数i对应的值ma[i]为数i首次出现的位置(没有出现就是n+1)

如果把询问按左端点排序,这样就转化为:修改:...;询问:询问[1,r]的答案

修改问题不大

询问[1,r]就转化为查询当前权值线段树上最小的数i,其对应的ma[i]>r;维护一下区间最大值,然后线段树上二分即可

可持久化一下线段树,还可以支持在线

。。。好吧可持久化的话有点卡空间,发现mex一定<=n,那么线段树可以少开一点

哎,还是思路不够灵活啊...

跑的极其慢?

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 #include<map>
 6 using namespace std;
 7 #define fi first
 8 #define se second
 9 #define mp make_pair
10 #define pb push_back
11 typedef long long ll;
12 typedef unsigned long long ull;
13 typedef pair<int,int> pii;
14 namespace S
15 {
16 const int N=8000000;
17 int maxn[N],lc[N],rc[N];
18 int mem;
19 int getnode(int f)
20 {
21     int t=++mem;
22     maxn[t]=maxn[f];lc[t]=lc[f];rc[t]=rc[f];
23     return t;
24 }
25 void setx(int L,int x,int l,int r,int &num)
26 {
27     num=getnode(num);
28     if(l==r)    {maxn[num]=x;return;}
29     int mid=l+((r-l)>>1);
30     if(L<=mid)    setx(L,x,l,mid,lc[num]);
31     else    setx(L,x,mid+1,r,rc[num]);
32     maxn[num]=max(maxn[lc[num]],maxn[rc[num]]);
33 }
34 int getx(int R,int l,int r,int num)
35 {
36     if(l==r)    return l;
37     int mid=l+((r-l)>>1);
38     if(maxn[lc[num]]>R)    return getx(R,l,mid,lc[num]);
39     else    return getx(R,mid+1,r,rc[num]);
40 }
41 }
42 int rt[200100];
43 int a[200100],nxt[200100];
44 int n,m;
45 map<int,int> ma;
46 const int ld=0,rd=200000;
47 int main()
48 {
49     int i,l,r;
50     S::maxn[0]=0x3f3f3f3f;
51     scanf("%d%d",&n,&m);
52     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
53     for(i=n;i>=1;i--)
54     {
55         nxt[i]=ma.count(a[i])?ma[a[i]]:n+1;
56         ma[a[i]]=i;
57         if(a[i]<=n)    S::setx(a[i],i,ld,rd,rt[1]);
58         //printf("1a %d %d\n",a[i],i);
59     }
60     for(i=2;i<=n;i++)
61     {
62         rt[i]=rt[i-1];
63         if(a[i-1]<=n)    S::setx(a[i-1],nxt[i-1],ld,rd,rt[i]);
64         //printf("%da %d %d\n",i,a[i-1],nxt[i-1]);
65     }
66     while(m--)
67     {
68         scanf("%d%d",&l,&r);
69         printf("%d\n",S::getx(r,ld,rd,rt[l]));
70     }
71     return 0;
72 }

 

posted @ 2018-09-02 21:52  hehe_54321  阅读(173)  评论(0编辑  收藏  举报
AmazingCounters.com