POJ 2104 寻找区间第K数
划分树,时间复杂度O(MlogN),归并树,时间复杂度O(Mlog^3N)。
归并树
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")
using namespace std;
const int MAX = 100010;
class Merger_tree{
public :
class Tnode{
public :
int l,r;
int len() { return r - l;}
int mid() { return MID(l,r);}
bool in(int ll,int rr) { return l >= ll && r <= rr; }
void lr(int ll,int rr){ l = ll; r = rr;}
};
Tnode node[MAX<<2];
int seg[20][MAX],a[MAX],n;
void init()
{
memset(seg,0,sizeof(seg));
memset(node,0,sizeof(node));
}
void build(int s,int t){ n = t; Merger_build(1,s,t,1); }
int find(int x,int y,int k) { return find_rank(n,x,y,k); };
void Merger_build(int t,int l,int r,int deep)
{
node[t].lr(l, r);
if( node[t].len() == 0 )
{
seg[deep][l] = a[l];
return ;
}
int mid = MID(l, r);
Merger_build(L(t), l, mid, deep+1);
Merger_build(R(t), mid+1, r, deep+1);
int k = l,i = l,j = mid+1;
while( i <= mid && j <= r )
if( seg[deep+1][i] < seg[deep+1][j] )
seg[deep][k++] = seg[deep+1][i++];
else
seg[deep][k++] = seg[deep+1][j++];
while( i <= mid )
seg[deep][k++] = seg[deep+1][i++];
while( j <= r )
seg[deep][k++] = seg[deep+1][j++];
}
int find_k(int t,int l,int r,int deep,int val)
{
if( node[t].in(l,r) )
{
int ll = node[t].l, rr = node[t].r;
while( ll < rr )
{
int mid = MID(ll, rr);
if( seg[deep][mid] < val )
ll = mid + 1;
else
rr = mid;
}
if( seg[deep][ll] <= val )
return ll - node[t].l + 1;
else
return ll - node[t].l;
}
if( node[t].len() == 0 ) return 0;
int ans = 0;
int mid = node[t].mid();
if( l <= mid ) ans += find_k(L(t), l, r, deep+1, val);
if( r >= mid ) ans += find_k(R(t), l, r, deep+1, val);
return ans;
}
int find_rank(int n,int x,int y,int k)
{
int l = 1,r = n;
while( l < r )
{
int mid = MID(l, r);
if( find_k(1, x, y, 1, seg[1][mid]) < k )
l = mid + 1;
else
r = mid;
}
return seg[1][l];
}
};
Merger_tree t;
int main()
{
int n,m,x,y,k;
while( ~scanf("%d%d",&n,&m) )
{
t.init();
for(int i=1; i<=n; i++)
scanf("%d",&t.a[i]);
t.build(1,n);
while( m-- )
{
scanf("%d%d%d",&x,&y,&k);
int ans = t.find(x,y,k);
printf("%d\n",ans);
}
}
return 0;
}
划分树
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")
using namespace std;
const int MAX = 100010;
class Parti_tree{
public :
class Tnode{
public :
int l,r;
int len() { return r - l;}
int mid() { return MID(l,r);}
bool in(int ll,int rr) { return l >= ll && r <= rr; }
void lr(int ll,int rr){ l = ll; r = rr;}
};
Tnode node[MAX<<2];
int Left[20][MAX], seg[20][MAX], sa[MAX];
void init()
{
memset(Left,0,sizeof(Left));
memset(node,0,sizeof(node));
}
void build(int s,int t){ sort(sa+1,sa+t+1); Parti_build(1,s,t,1); }
int find(int s,int t,int k){ return find_rank(1,s,t,1,k); }
void Parti_build(int t,int l,int r,int d)
{
node[t].lr(l, r);
if( node[t].len() == 0 ) return ;
int mid = MID(l, r), lsame = mid - l + 1;
for(int i=l; i<=r; i++)
if( seg[d][i] < sa[mid] )
lsame--;
int lpos = l,rpos = mid+1,same = 0;
for(int i=l; i<=r; i++)
{
if( i == l )
Left[d][i] = 0;
else
Left[d][i] = Left[d][i-1];
if( seg[d][i] < sa[mid] )
{
Left[d][i]++;
seg[d+1][lpos++] = seg[d][i];
}
if( seg[d][i] > sa[mid] )
seg[d+1][rpos++] = seg[d][i];
if( seg[d][i] == sa[mid] )
if( same < lsame )
{
same++;
Left[d][i]++;
seg[d+1][lpos++] = seg[d][i];
}
else
seg[d+1][rpos++] = seg[d][i];
}
Parti_build(L(t), l, mid, d+1);
Parti_build(R(t), mid+1, r, d+1);
}
int find_rank(int t,int l,int r,int d,int val)
{
if( node[t].len() == 0 )
return seg[d][l];
int s,ss;
if( l == node[t].l )
{
s = Left[d][r];
ss = 0;
}
else
{
s = Left[d][r] - Left[d][l-1];
ss = Left[d][l-1];
}
if( s >= val )
return find_rank(L(t), node[t].l+ss, node[t].l+ss+s-1, d+1, val);
else
{
int mid = node[t].mid();
int bb = l - node[t].l - ss;
int b = r - l + 1 - s;
return find_rank(R(t), mid+bb+1, mid+bb+b,d+1,val-s);
}
}
};
Parti_tree t;
int main()
{
int n,m,x,y,k;
while( ~scanf("%d%d",&n,&m) )
{
t.init();
for(int i=1; i<=n; i++)
{
scanf("%d",&t.sa[i]);
t.seg[1][i] = t.sa[i];
}
t.build(1,n);
while( m-- )
{
scanf("%d%d%d",&x,&y,&k);
int ans = t.find(x, y, k);
printf("%d\n",ans);
}
}
return 0;
}