习题:列队(主席树)
题目
思路
考虑如果有一群人直往右跑,那么设$aim_i \(为最优策略下其的终止位置,设\)p_i\(为他们现在的位置,按照题目给定的式子,消耗的体力值总和即为\)\sum_{i=1}^{m}|aim_i-p_i|$
因为对于所有的人都有\(aim_i>p_i\),所以原式即为\(\sum_{i=1}^{m}aim_i-\sum_{i=1}^{m}p_i\),也就是指他们的互相的位置其实对答案没有什么影响,贪心地去考虑,一定有一个分界点,其左边的所有人向右跑且不会超过分界点,右边的所有人向左跑,且不会超过分界点。那么考虑一颗主席树,方便裂出\(l\sim r\)中的所有点,这里的主席树是按照权值来的,所以可以在主席树上进行二分,把求出分界点的时间从\(log_nlog_n\)变成\(log_n\),值域范围需要开两倍
代码
#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
using namespace std;
#define pii pair<long long,int>
#define x first
#define y second
namespace IO
{
void read(int &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(long long x)
{
if(x>9)
write(x/10);
putchar(x%10+'0');
}
}
namespace lst
{
inline pii operator + (const pii &a,const pii &b)
{
return make_pair(a.x+b.x,a.y+b.y);
}
int cnt;
struct node
{
int l,r;
int lson,rson;
int siz;
long long val;
}tre[1000000*30+5];
void build(int l,int r,int &k)
{
k=++cnt;
tre[k].l=l;
tre[k].r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build(l,mid,tre[k].lson);
build(mid+1,r,tre[k].rson);
tre[k].siz=tre[tre[k].lson].siz+tre[tre[k].rson].siz;
tre[k].val=tre[tre[k].lson].val+tre[tre[k].rson].val;
}
void change(int las,int &now,int val,int pos)
{
if(tre[las].l>pos||pos>tre[las].r)
return;
now=++cnt;
tre[now]=tre[las];
if(tre[now].l==tre[now].r)
{
tre[now].val+=val;
tre[now].siz++;
return;
}
change(tre[las].lson,tre[now].lson,val,pos);
change(tre[las].rson,tre[now].rson,val,pos);
tre[now].siz=tre[tre[now].lson].siz+tre[tre[now].rson].siz;
tre[now].val=tre[tre[now].lson].val+tre[tre[now].rson].val;
}
pii ask(int las,int now,int l,int r)
{
if(tre[now].l>r||l>tre[now].r)
return make_pair(0,0);
if(l<=tre[now].l&&tre[now].r<=r)
return make_pair(tre[now].val-tre[las].val,tre[now].siz-tre[las].siz);
return ask(tre[las].lson,tre[now].lson,l,r)+ask(tre[las].rson,tre[now].rson,l,r);
}
long long calc(int las,int now,int k,int add,int dis)
{
int siz=tre[tre[now].lson].siz-tre[tre[las].lson].siz+add;
int mid=tre[tre[now].lson].r;
if(mid<k)
return calc(tre[las].rson,tre[now].rson,k,siz,dis);
if(mid>k+dis)
return calc(tre[las].lson,tre[now].lson,k,add,dis);
if(siz==mid-k)
return mid;
if(siz>mid-k)
return calc(tre[las].rson,tre[now].rson,k,siz,dis);
else
return calc(tre[las].lson,tre[now].lson,k,add,dis);
}
}
using namespace lst;
using namespace IO;
int n,m;
int rt[500005];
int l,r,k;
long long s[2000005];
int main()
{
read(n);
read(m);
build(1,2000000,rt[0]);
for(int i=1;i<=2000000;i++)
s[i]=s[i-1]+i;
for(int i=1,val;i<=n;i++)
{
read(val);
change(rt[i-1],rt[i],val,val);
}
for(int i=1;i<=m;i++)
{
read(l);
read(r);
read(k);
int d=calc(rt[l-1],rt[r],k-1,0,r-l+1);
pii t1=ask(rt[l-1],rt[r],1,d);
pii t2=ask(rt[l-1],rt[r],d+1,2000000);
write(((s[d]-s[k-1])-t1.x)+(t2.x-(s[k+r-l]-s[d])));
putchar('\n');
}
return 0;
}

浙公网安备 33010602011771号