标签:等价 \n merge efi str scanf 分治 有序 ons
例1. 给定序列, 2种操作, (1)单点加 (2)区间求和
询问看成二维键值对$(t,x)$, $t$为操作时间, $x$为操作位置, 区间求和转化为两个前缀求和做差, 那么问题就等价于求所有$tt\le t$, $xx\le x$的权值和, 也就是一个二维偏序问题, 时间已经默认有序, 直接对操作位置归并排序一次即可求出. 要注意操作位置相同时, 询问操作要排在前面.
#include <iostream>
#include <algorithm>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
using namespace std;
const int N = 3e6+10;
int n, m, tot, totx;
struct _ {
int type,id,v;
bool operator < (const _ &rhs) const {
return id<rhs.id||id==rhs.id&&type<rhs.type;
}
} q[N], tmp[N];
int ans[N];
void merge(int l, int r) {
if (l==r) return;
int mid = l+r>>1;
merge(l,mid),merge(mid+1,r);
int p1=l, p2=mid+1, s=0;
REP(i,l,r) {
if (p2>r||(p1<=mid&&q[p1]<q[p2])) {
if (q[p1].type==0) s+=q[p1].v;
tmp[i]=q[p1++];
}
else {
if (q[p2].type==2) ans[q[p2].v]+=s;
else if (q[p2].type==1) ans[q[p2].v]-=s;
tmp[i]=q[p2++];
}
}
REP(i,l,r) q[i]=tmp[i];
}
int main() {
scanf("%d%d", &n, &m);
REP(i,1,n) {
++tot;
scanf("%d", &q[tot].v);
q[tot].id = i;
}
REP(i,1,m) {
int op, l, r, x, v;
scanf("%d", &op);
if (op==1) {
scanf("%d%d", &x, &v);
q[++tot]={0,x,v};
}
else {
++totx,scanf("%d%d", &l, &r);
q[++tot]={1,l-1,totx};
q[++tot]={2,r,totx};
}
}
merge(1,tot);
REP(i,1,totx) printf("%d\n", ans[i]);
}
例2. 给定n个三元组, 对于每个三元组(x,y,z), 求有多少三元组$(x_0,y_0,z_0)$, 满足$x<x_0,y<y_0,z<z_0$
标签:等价 \n merge efi str scanf 分治 有序 ons
原文地址:https://www.cnblogs.com/uid001/p/10699963.html