習題:列隊(主席樹)
阿新 • • 發佈:2020-09-16
題目
思路
考慮如果有一群人直往右跑,那麼設$aim_i $為最優策略下其的終止位置,設$p_i$為他們現在的位置,按照題目給定的式子,消耗的體力值總和即為$\sum_^|aim_i-p_i|$
因為對於所有的人都有$aim_i>p_i$,所以原式即為$\sum_aim_i-\sum_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; }