生活随笔
收集整理的這篇文章主要介紹了
P4559 [JSOI2018]列队 主席树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
給你nnn個學生以及其位置,mmm個詢問,每次詢問[l,r][l,r][l,r]的學生跑到[k,k+r?l][k,k+r-l][k,k+r?l]的位置的最小總的移動距離。當然不同的學生不能站在同一位置。
n,m≤5e5,1≤ai,k≤1e6n,m\le5e5,1\le a_i,k\le1e6n,m≤5e5,1≤ai?,k≤1e6。
思路:
首先[l,r][l,r][l,r]的學生相對位置不變一定是最優的,所以一定在[k,k+r?l][k,k+r-l][k,k+r?l]之間有一個分界點,左邊的人都往右跑,右邊的往左跑是最優的,我們發現這個是可以在主席樹上二分找的。
首先在主席樹上拿出來[l,r][l,r][l,r]的學生的位置以及個數,分以下四種情況:
(1)(1)(1)如果當前區間沒有人,直接返回。
(2)(2)(2)如果當前區間的人都應該往左跑,那么直接計算學生總位置和?-?應該到的位置。
(3)(3)(3)如果當前區間的人都應該往右跑,那么直接計算應該到的位置?-?學生總位置和。
(4)(4)(4)不能確定學生方向,那么遞歸子樹處理。
上面計算應該到的位置就是利用等差數列求和公式cnt?(st+st+cnt?1)/2cnt*(st+st+cnt-1)/2cnt?(st+st+cnt?1)/2即可。
復雜度有人證明過是O(nlogn)O(nlogn)O(nlogn)的。
// Problem: P4559
[JSOI2018
]列隊
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4559
// Memory Limit:
500 MB
// Time Limit:
3000 ms
//
// Powered by CP Editor
(https://cpeditor.org
)//
//
//
using namespace std
;//void
rd_cre() { freopen
("d://dp//data.txt",
"w",stdout
); srand
(time
(NULL
)); }
//void
rd_ac() { freopen
("d://dp//data.txt",
"r",stdin
); freopen
("d://dp//AC.txt",
"w",stdout
); }
//void
rd_wa() { freopen
("d://dp//data.txt",
"r",stdin
); freopen
("d://dp//WA.txt",
"w",stdout
); }typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int
> PII
;const int
N=1000010,mod
=1e9+7,INF
=0x3f3f3f3f
;
const double
eps=1e-6
;int n,m
;
int root
[N
],tot
;
struct Node
{int l,r
;int cnt
;LL
sum;
}tr
[N*40
];void insert
(int p,int
&q,int l,int r,int pos
) {q=++tot
; tr
[q
]=tr
[p
];tr
[q
].cnt++
; tr
[q
].sum
+=pos
;if
(l
==r
) return;int
mid=(l+r
)>>1;if
(pos
<=mid
) insert
(tr
[p
].l,tr
[q
].l,l,mid,pos
);else insert
(tr
[p
].r,tr
[q
].r,mid+1,r,pos
);
}LL query
(int p,int q,int l,int r,int add,int k
) {if
(tr
[q
].cnt-tr
[p
].cnt
==0) return 0ll
;int
cnt=tr
[q
].cnt-tr
[p
].cnt
; LL
sum=tr
[q
].sum-tr
[p
].sum
;if
(l
>=k+add
) return sum-
(1ll*k*2+add*2+cnt-1
)*cnt/2
;if
(r
<=k+add+cnt-1
) return (1ll*k*2+add*2+cnt-1
)*cnt/2-sum
;cnt=tr
[tr
[q
].l
].cnt-tr
[tr
[p
].l
].cnt
;int
mid=(l+r
)>>1;return query
(tr
[p
].l,tr
[q
].l,l,mid,add,k
)+query
(tr
[p
].r,tr
[q
].r,mid+1,r,add+cnt,k
);
}int
main()
{
// ios::sync_with_stdio
(false
);
// cin.tie
(0);scanf
("%d%d",
&n,
&m
);for
(int
i=1;i
<=n
;i++
) {int x
; scanf
("%d",
&x
);insert
(root
[i-1
],root
[i
],1,1000000,x
);}while
(m--
) {int l,r,k
; scanf
("%d%d%d",
&l,
&r,
&k
);printf
("%lld\n",query
(root
[l-1
],root
[r
],1,1000000,0,k
));}return 0;
}
/**/
總結
以上是生活随笔為你收集整理的P4559 [JSOI2018]列队 主席树的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。