# Niuke challenge 48 E Speed Forwarding (tree over tree)

Keywords: C++ data structure

The given length is n n Sequence of n a a a. Altogether m m m operations, there are two operations:

1. Given l , r , k l,r,k l. R, K, satisfied in the query interval S ( x ) > = k S(x)>=k Maximum of S (x) > = k x ( x ∈ [ 0 , 1 0 5 ] ) x(x \in [0,10^5]) x(x ∈ ), S function is defined as S ( x ) = ∑ i = l r max ⁡ ( a i − x , 0 ) S(x)=\sum_{i=l}^{r} \max(a_{i}-x,0) S(x)=∑i=lr​max(ai​−x,0).

2. Given p , k p,k p. K, will a p a_{p} ap ， amend to read k k k.

Pre knowledge: Chairman tree, tree array, tree nest tree, dynamic open point line segment tree.

First, observe S S The definition of S function can be found S S Value and interval of S function [ l , r ] [l,r] The value range of [l,r] is related. What we need to maintain is greater than x x x (two points) x x x) Sum of all numbers s u m sum sum and number n u m num num, and then the result S ( x ) = ∑ i = l r s u m − x ∗ n u m S(x)=\sum_{i=l}^{r} sum-x*num S(x) = Σ i=lr sum − x * num, comparison S ( x ) S(x) Is the value of S(x) function greater than k k k can continue to score two points. So maintaining the chairman tree of interval value domain is obviously a good choice. However, there is a second modification operation, so we need to dynamically modify our chairman tree.

Dynamic modification is also easy** Let's first consider a problem. Given a sequence, we ask the interval many times [ l , r ] [l,r] The sum of [l,r]. Obviously, we can do this directly, but if the modification operation is added at this time, we can use the tree array to maintain the prefix and. In fact, that's what a tree means. The static chairman tree maintains the prefix and. Now there are modification operations. We use the tree array to maintain the prefix and of the chairman tree, and we can achieve the dynamic chairman tree** Because a tree array is set on the basis of the chairman tree, the complexity of a single query modification is O ( log ⁡ 2 n ) O(\log^2{n}) O(log2n). Therefore, the complexity of the whole process is O ( n log ⁡ 2 n ) O(n \log^2{n}) O(nlog2n), but the query operation is binary x x x. It will lead to query complexity band 3 3 3 log ⁡ \log log, it's obviously hard to 1 0 5 10^5 Under the data of 105 3 s 3s Run in 3 seconds.

After careful observation, we found that in fact, we were at two points each time x x After x, the interval is searched [ l , r ] [l,r] [l,r] greater than or equal to x x Function value of x S ( x ) S(x) S(x) to judge, but since the segment tree (the chairman tree is actually a lot of segment trees) is essentially dichotomy, we don't need to dichotomy in the outer layer x x x. You only need to calculate whether the maximum function value on the right is greater than k until you want to jump there, and finally jump to l = = r l==r The position of l==r is the answer. from S ( x ) = ∑ i = l r a i ∗ [ a i > m i d ] − x ∗ ∑ i = l r [ a i > m i d ] > = k S(x)=\sum_{i=l}^{r} a_{i}*[a_{i}>mid]-x*\sum_{i=l}^{r}[a_{i}>mid]>=k S(x) = Σ i=lr ai ∗ [ai > mid] − x ∗Σi=lr [ai > mid] > = k x x When x is the smallest, the function value is the largest (where m i d mid mid refers to the right interval (or right range) greater than the midpoint x x x take m i d + 1 mid+1 When mid+1, judge whether it is greater than or equal to k k k is enough. Then the query complexity is compressed to O ( n ∗ log ⁡ 2 n ) O(n*\log^2{n}) O(n∗log2n). So you can pass this question happily.

Details: note that the value sum and the number of points of the right value field must be retained when jumping to the left subtree, because the value of the right value field will not be included in the next calculation when jumping to the left subtree, and it needs to be retained as a parameter.

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int N=1e5;

ll sum[maxn<<7],a[maxn],n,m,op,u,v,w;
int ls[maxn<<7],rs[maxn<<7],sz[maxn<<7],rt[maxn],now;
int qx,tx,qy,ty;

template<class T>inline
{
x=0; char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return ch!=EOF;
}

template<class A,class...B>inline
{
}

template<class T>inline
void print(T x)
{
if(x<0)putchar('-'),x=-x;
int t={0},pos=0;
while(x)t[++pos]=x%10,x/=10;
if(!pos)putchar('0');
else while(pos)putchar(t[pos--]+'0');
return;
}

template<class T>inline
void print(T x,char ch)
{
print(x),putchar(ch);
}

inline int lowbit(int x)
{
return x&(-x);
}

int update(int&t,int l,int r,ll pos,ll up)
{
if(!t)t=++now;
sum[t]+=pos*up,sz[t]+=up;
if(l==r)return t;
int mid=l+r>>1;
if(pos<=mid)update(ls[t],l,mid,pos,up);
else update(rs[t],mid+1,r,pos,up);
return t;
}

ll query(int l,int r,ll as,ll az,ll k)
{
if(l==r)return l;
int mid=l+r>>1;
ll sml=0,nml=0,smr=0,nmr=0,sm,nm;
for(int i=1;i<=tx;i++)sml+=sum[rs[qx[i]]],nml+=sz[rs[qx[i]]];
for(int i=1;i<=ty;i++)smr+=sum[rs[qy[i]]],nmr+=sz[rs[qy[i]]];
sm=smr-sml,nm=nmr-nml;
if(as+sm-(nm+az)*(mid+1)<k)
{
for(int i=1;i<=tx;i++)qx[i]=ls[qx[i]];
for(int i=1;i<=ty;i++)qy[i]=ls[qy[i]];
return query(l,mid,as+sm,az+nm,k);
}
else
{
for(int i=1;i<=tx;i++)qx[i]=rs[qx[i]];
for(int i=1;i<=ty;i++)qy[i]=rs[qy[i]];
return query(mid+1,r,as,az,k);
}
return -1;
}

void modify(int x,ll pos,ll up)
{
for(int i=x;i<=n;i+=lowbit(i))
{
rt[i]=update(rt[i],-1,N,pos,up);
}
return;
}

int main()
{
//  	freopen("LCA.in","r",stdin);
for(int i=1;i<=n;i++)
{
modify(i,a[i],1);
}
for(int i=1;i<=m;i++)
{
if(!op)
{
for(int j=u-1;j>=1;j-=lowbit(j))qx[++tx]=rt[j];
for(int j=v;j>=1;j-=lowbit(j))qy[++ty]=rt[j];
print(query(-1,N,0,0,w),'\n');
}
else
{
modify(u,a[u],-1);
modify(u,v,1);
a[u]=v;
}
}
return 0;
}


Posted by somenoise on Tue, 09 Nov 2021 03:55:05 -0800