//https://codeforces.com/gym/104053/problem/E
结构体封装了两棵线段树,实测比不封装块!
pre.query(1,1,p,1,len) 是目前比b[p]小的数的总和!b为a的离散化数组!
pre.query_cnt(1,1,p,1,len) 是目前比b[p]小的数字的个数!
nex.query(1,1,p,1,len) 是总共比b[p]小的数字总和!
nex.query_cnt(1,1,p,1,len) 是总共比b[p]小的数字的总和!
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<map>
#include<unordered_map>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int N = 1e6+9;
int a[N],b[N];
int n,m;
struct SegmentTree {
ll sum[N << 2];
int cnt[N <<2 ];
void pushup(int u) {
sum[u] = sum[u<<1] + sum[u<<1|1];
cnt[u] = cnt[u<<1] + cnt[u<<1|1];
}
void build(int u,int l,int r) {
sum[u] = 0,cnt[u] = 0;
if(l == r) return;
int mid = l + r >> 1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void modify(int u,int x,int c,int l,int r) {
if(l == x && r == x) {
sum[u] += c;
cnt[u]++;
return;
}
int mid = l + r >> 1;
if(x <= mid) modify(u<<1,x,c,l,mid);
else modify(u<<1|1,x,c,mid+1,r);
pushup(u);
}
ll query(int u,int l,int r,int L,int R) {
if(l <= L && r >= R) {
return sum[u];
}
ll ans = 0;
int mid = L + R >> 1;
if(l <= mid) ans = query(u<<1,l,r,L,mid);
if(r > mid) ans += query(u<<1|1,l,r,mid+1,R);
return ans;
}
ll query_cnt(int u,int l,int r,int L,int R) {
if(l <= L && r >= R) {
return cnt[u];
}
ll ans = 0;
int mid = L + R >> 1;
if(l <= mid) ans = query_cnt(u<<1,l,r,L,mid);
if(r > mid) ans += query_cnt(u<<1|1,l,r,mid+1,R);
return ans;
}
}pre,nex;
int main() {
ios_base :: sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i=1; i<=n; i++) cin >> a[i],b[i] = a[i];
sort(b+1,b+n+1);
int len = unique(b+1,b+n+1) - b - 1;
nex.build(1,1,len);
pre.build(1,1,len);
for(int i=1; i<=n; i++) {
int p = lower_bound(b+1,b+len+1,a[i]) - b;
nex.modify(1,p,a[i],1,len);
}
for(int i=1; i<=n; i++) {
int p = lower_bound(b+1,b+len+1,a[i]) - b;
pre.modify(1,p,a[i],1,len);
ll t1 = pre.query(1,1,p,1,len);
ll t2 = nex.query(1,1,p,1,len);
ll cnt1 = pre.query_cnt(1,1,p,1,len);
ll cnt2 = nex.query_cnt(1,1,p,1,len);
ll ans1 = 1LL*a[i] * (cnt1 - 1) - (t1 - a[i]) + cnt1 - 1;
ll ans2 = 1LL*a[i] * (cnt2 - cnt1) - (t2 - t1);
ll ans = ans1 + ans2;
if(ans <= m-2) cout<<ans<<"\n";
else cout<<-1<<"\n";
}
return 0;
}
动态开点权值线段树带有区间修改
无build()函数,还不太清楚!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 1e9+7;
const int MAXN = 1e5+9;
struct Node {
int cnt,del,lc,rc;
}tree[MAXN * 50];
int tot;
void pushup(int u) {
tree[u].cnt = tree[tree[u].lc].cnt + tree[tree[u].rc].cnt;
}
void movetag(int u) {
tree[u].del = 1;
tree[u].cnt = 0;
}
void pushdown(int u) {
if(tree[u].del) {
tree[u].del = 0;
movetag(tree[u].lc);
movetag(tree[u].rc);
}
}
void insert(int u,int l,int r,int x) {
if(l == r) {
tree[u].del = 0;
tree[u].cnt++;
return;
}
pushdown(u);
int mid = l + r >> 1;
if(x <= mid) {
if(tree[u].lc == 0) tree[u].lc = ++tot;
insert(tree[u].lc,l,mid,x);
} else {
if(tree[u].rc == 0) tree[u].rc = ++tot;
insert(tree[u].rc,mid+1,r,x);
}
pushup(u);
}
void modify(int u,int lc,int rc,int l,int r) {
if(u == 0 || tree[u].del == 1 || tree[u].cnt == 0) return;
if(l <= lc && r >= rc) {
tree[u].del = 1;
tree[u].cnt = 0;
return;
}
int mid = lc + rc >> 1;
pushdown(u);
if(l <= mid) {
modify(tree[u].lc,lc,mid,l,r);
}
if(r > mid) {
modify(tree[u].rc,mid+1,rc,l,r);
}
pushup(u);
}
int query_sum(int u,int lc,int rc,int l,int r) {
if(u == 0 || tree[u].del == 1 || tree[u].cnt == 0) return 0;
if(l <= lc && r >= rc) return tree[u].cnt;
pushdown(u);
int sum = 0;
int mid = lc + rc >> 1;
if(l <= mid) sum = query_sum(tree[u].lc,lc,mid,l,r);
if(r > mid) sum += query_sum(tree[u].rc,mid+1,rc,l,r);
return sum;
}
int query_k(int u,int lc,int rc,int l,int r,int k) {
if(u == 0 || tree[u].cnt == 0 || tree[u].del == 1) return -1;
if(lc == rc) {
if(tree[u].cnt >= k) return lc;
else return -1;
}
pushdown(u);
int cnt = 0;
int mid = lc + rc >> 1;
if(r > mid) {
cnt = query_sum(tree[u].rc,mid+1,rc,l,r);
if(cnt >= k) return query_k(tree[u].rc,mid+1,rc,l,r,k);
}
if(l <= mid) {
return query_k(tree[u].lc,lc,mid,l,r,k - cnt);
}
return - 1;
}
int main() {
tot = 1;
int n;
cin >> n;
for(int i=1; i<=n; i++) {
int op,l,r,k;
scanf("%d",&op);
if(op == 1) {
int x;
scanf("%d",&x);
insert(1,1,INF,x);
} else if(op == 2) {
scanf("%d%d",&l,&r);
modify(1,1,INF,l,r);
} else {
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query_k(1,1,INF,l,r,k));
}
}
return 0;
}
权值线段树!
https://codeforces.com/contest/1042/problem/D
题目大意:
给定一段序列,求满足条件的部分子段序列和小于t的个数!
容易想到前缀和,题目要求等价于 sum[r] - sum[l-1] < t;
然后枚举l,r 但是这样也只能将复杂度n3降到n2,继续考虑将式子变形: sum[r] < t + sum[l-1];
离散化后建立权值线段树,求满足条件r的个数!
枚举l,log查询r,时间复杂度 nlog(n),写出超多bug吐~;
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+9;
typedef long long ll;
ll a[N],b[N];
ll sum[N];
ll n,t;
struct Segmentree
{
int l,r,v;
} tr[N<<2];
void pushup(int u)
{
tr[u].v = tr[u<<1].v + tr[u<<1|1].v;
}
void build(int u,int l,int r)
{
tr[u] = {l,r,0};
if(l == r) return;
int mid = l + r >> 1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void modify(int u,int x)
{
if(tr[u].l == x && tr[u].r == x)
{
tr[u].v++;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u<<1,x);
else modify(u<<1|1,x);
pushup(u);
}
void change(int u,int x)
{
if(tr[u].l == x && tr[u].r == x)
{
tr[u].v--;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) change(u<<1,x);
else change(u<<1|1,x);
pushup(u);
}
ll query(int u,int l,int r)
{
if(l <= tr[u].l && r >= tr[u].r)
{
return tr[u].v;
}
ll ans = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) ans = query(u<<1,l,r);
if(r > mid) ans += query(u<<1|1,l,r);
return ans;
}
int main()
{
cin >> n >> t;
for(int i=1; i<=n; i++) scanf("%lld",&a[i]),sum[i] = sum[i-1] + a[i],b[i] = sum[i];
sort(b+1,b+n+1);
int len = unique(b+1,b+n+1) - b - 1;
build(1,1,n); //建树len不就可以了吗?
for(int i=1; i<=n; i++)
{
int temp = lower_bound(b+1,b+len+1,sum[i]) - b;
modify(1,temp);
}
ll ans = 0;
for(int l=1; l<=n; l++)
{
ll x = t + sum[l-1] - 1;
int temp = upper_bound(b+1,b+len+1,x) - b - 1;
if(temp >= 1 && temp <= n) ans += query(1,1,temp);
temp = upper_bound(b+1,b+len+1,sum[l]) - b - 1;
if(temp >= 1 && temp <= n) change(1,temp);
}
cout<<ans<<"\n";
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=1394
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+9;
int a[N];
typedef long long ll;
int n,len;
struct Segmentree {
int l,r;
int v;
}tr[N<<2];
void pushup(int u) {
tr[u].v = tr[u<<1].v + tr[u<<1|1].v;
}
void build(int u,int l,int r) {
tr[u].l = l,tr[u].r = r,tr[u].v = 0;
if(l == r) return;
int mid = l + r >> 1;
build(u<<1,l,mid),build(u<<1 | 1,mid+1,r);
}
void modify(int u,int x) {
if(tr[u].l == x && tr[u].r == x) {
tr[u].v++;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u<<1,x);
else modify(u<<1|1,x);
pushup(u);
}
ll query(int u,int l,int r) {
if(l <= tr[u].l && r >= tr[u].r) return tr[u].v;
int mid = tr[u].l + tr[u].r >> 1;
ll ans = 0;
if(l <= mid) ans = query(u<<1,l,r);
if(r > mid) ans += query(u<<1|1,l,r);
return ans;
}
int main() {
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
build(1,0,n-1);
ll sum = 0;
for(int i=1; i<=n; i++) {
sum += query(1,a[i]+1,n-1);
modify(1,a[i]);
}
ll minn =sum;
for(int i=1;i<=n-1;i++) {
sum += (n-a[i]-1)-a[i];
minn = min(minn,sum);
}
printf("%lld\n",minn);
}
return 0;
}
权值线段树求逆序对!
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+9;
int a[N],b[N];
typedef long long ll;
int n,len;
struct Segmentree {
int l,r;
int v;
}tr[N<<2];
void pushup(int u) {
tr[u].v = tr[u<<1].v + tr[u<<1|1].v;
}
void build(int u,int l,int r) {
tr[u].l = l,tr[u].r = r;
if(l == r) return;
int mid = l + r >> 1;
build(u<<1,l,mid),build(u<<1 | 1,mid+1,r);
}
void modify(int u,int x) {
if(tr[u].l == x && tr[u].r == x) {
tr[u].v++;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u<<1,x);
else modify(u<<1|1,x);
pushup(u);
}
ll query(int u,int l,int r) {
if(l <= tr[u].l && r >= tr[u].r) return tr[u].v;
int mid = tr[u].l + tr[u].r >> 1;
ll ans = 0;
if(l <= mid) ans = query(u<<1,l,r);
if(r > mid) ans += query(u<<1|1,l,r);
return ans;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
b[i] = a[i];
}
build(1,1,n);
sort(b+1,b+n+1);
len = unique(b+1,b+n+1) - b - 1;
ll ans = 0;
for(int i=1; i<=n; i++) {
int temp = lower_bound(b+1,b+len+1,a[i]) - b;
if(temp != n) ans += query(1,temp+1,n); //这里不特判应该也不会RE!
modify(1,temp);
}
cout<<ans<<"\n";
return 0;
}