模板
网上很多博客都有一开始建空树的操作,实际上这一步是可以省去的。省去后功能不仅不会受到影响,同时在处理多组数据的时候还能省下不少时间(见下文HDU 6621)。
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 200010;
int node_cnt, n, m;
int sum[MAXN*40], rt[MAXN], lc[MAXN*40], rc[MAXN*40];//线段树相关,乘数 > log(n)
int a[MAXN], b[MAXN];//原序列和离散序列
int p;//修改点
int modify(int pre, int l, int r)
{
int now = ++node_cnt;
lc[now] = lc[pre]; rc[now] = rc[pre]; sum[now] = sum[pre] + 1;
if(l == r)
return now;
int mid = (l + r) >> 1;
if(p <= mid) lc[now] = modify(lc[now], l, mid);
else rc[now] = modify(rc[now], mid+1, r);
return now;
}
int query(int u, int v, int l, int r, int k)
{
int ans, mid = ((l + r) >> 1), x = sum[lc[v]] - sum[lc[u]];
if(l == r)
return l;
if(x >= k) ans = query(lc[u], lc[v], l, mid, k);
else ans = query(rc[u], rc[v], mid+1, r, k-x);
return ans;
}
int main()
{
int l, r, k, q, ans;
while(~scanf("%d%d", &n, &m))
{
node_cnt=0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b+1, b+n+1);
q = unique(b+1, b+n+1) - b - 1; //离散化
//build(rt[0], 1, q);
for(int i = 1; i <= n; i++)
{
p = lower_bound(b+1, b+q+1, a[i])-b; //p为a[i]的排名
rt[i] = modify(rt[i-1], 1, q);
}
while(m--)
{
scanf("%d%d%d", &l, &r, &k);
ans = query(rt[l-1], rt[r], 1, q, k);
printf("%d\n", b[ans]);
}
}
return 0;
}
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 100010;
int node_cnt, n, m;
int sum[MAXN*40], rt[MAXN], lc[MAXN*40], rc[MAXN*40];//线段树相关,乘数 > log(n)
long long a[MAXN], b[MAXN];//原序列和离散序列
int p;//修改点
/*void build(int &t, int l, int r)
{
t = ++node_cnt;
if(l == r)
return;
int mid = (l + r) >> 1;
build(lc[t], l, mid);
build(rc[t], mid+1, r);
}*/
int modify(int pre, int l, int r)
{
int now = ++node_cnt;
lc[now] = lc[pre]; rc[now] = rc[pre]; sum[now] = sum[pre] + 1;
if(l == r)
return now;
int mid = (l + r) >> 1;
if(p <= mid) lc[now] = modify(lc[now], l, mid);
else rc[now] = modify(rc[now], mid+1, r);
return now;
}
int query(int u, int v, int l, int r, int k)
{
int ans, mid = ((l + r) >> 1), x = sum[rc[v]] - sum[rc[u]];
if(l == r)
return l;
if(x >= k) ans = query(rc[u], rc[v], mid+1, r, k);
else ans = query(lc[u], lc[v], l, mid, k-x);
return ans;
}
int main()
{
int l, r, q;
while(~scanf("%d%d", &n, &m))
{
node_cnt=0;
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
b[i] = a[i];
}
sort(b+1, b+n+1);
q = unique(b+1, b+n+1) - b - 1; //离散化
for(int i = 1; i <= n; i++)
{
p = lower_bound(b+1, b+q+1, a[i])-b; //p为a[i]的排名
rt[i] = modify(rt[i-1], 1, q);//建树
}
while(m--)
{
scanf("%d%d", &l, &r);
if(r-l+1<3){
printf("-1\n");
continue;
}
int tmp1 = query(rt[l-1], rt[r], 1, q, 1);
int tmp2 = query(rt[l-1], rt[r], 1, q, 2);
int tmp3 = query(rt[l-1], rt[r], 1, q, 3);
int rk = 3,flg = 1;
while(b[tmp2] + b[tmp3] <= b[tmp1])
{
if(rk >= r - l + 1){
flg = 0;
break;
}
tmp1 = tmp2; tmp2 = tmp3;
tmp3 = query(rt[l-1], rt[r], 1, q, ++rk);
}
if(flg)printf("%lld\n",b[tmp1]+b[tmp2]+b[tmp3]);
else printf("-1\n");
//printf("%d\n", b[ans]);
}
}
return 0;
}
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
int node_cnt, n, m;
int sum[MAXN*40], rt[MAXN], lc[MAXN*40], rc[MAXN*40];//线段树相关,乘数 > log(n)
int a[MAXN], b[MAXN];//原序列和离散序列
int p;//修改点
int ql,qr;
void build(int &t, int l, int r)
{
t = ++node_cnt;
if(l == r)
return;
int mid = (l + r) >> 1;
build(lc[t], l, mid);
build(rc[t], mid+1, r);
}
int modify(int pre, int l, int r)
{
int now = ++node_cnt;
lc[now] = lc[pre]; rc[now] = rc[pre]; sum[now] = sum[pre] + 1;
if(l == r)
return now;
int mid = (l + r) >> 1;
if(p <= mid) lc[now] = modify(lc[now], l, mid);
else rc[now] = modify(rc[now], mid+1, r);
return now;
}
int query(int u, int v, int l, int r)
{
//int ans, mid = ((l + r) >> 1), x = sum[lc[v]] - sum[lc[u]];
if(l >= ql && r <= qr) return sum[v] - sum[u];
int ret = 0, mid = ((l + r) >> 1);
if(ql <= mid) ret += query(lc[u],lc[v],l,mid);
if(qr >= mid+1) ret += query(rc[u],rc[v],mid+1,r);
return ret;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int l, r, p, k, q=1000000;
scanf("%d%d", &n, &m);
build(rt[0], 1, q);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
p = a[i];
modify(rt[i-1],1,q);
}
int ans=0;
while(m--)
{
scanf("%d%d%d%d", &l, &r, &p, &k);
l^=ans;r^=ans;p^=ans;k^=ans;
int L=0,R=q,mid;
while(L<R)
{
mid = (L + R) / 2;
ql = max(1, p - mid);
qr = min(q, p + mid);
int num = query(rt[l-1], rt[r], 1, q);
if(num >= k){
R = mid;
}else{
L = mid + 1;
}
}
printf("%d\n",L);
ans = L;
}
}
return 0;
}
上面的提交是省去建空树操作的,对比建空树节省将近一半的时间。
此题不建空树节省时间原因:建空树复杂度为O( 数据范围*log(数据范围)),此题由于不进行离散化操作,因此数据范围为1e6,多次建空树会消耗不少时间。