cdq分治解决偏序与整体二分解决区间k小思路相似,都是考虑左区间对右区间的影响,但是实现略有不同
偏序的重点是:理解两个有序链表的合并,即,一次归并排序
整体二分的重点是:二分权值,把操作(查询与修改)划分到左右区间,然后递归处理
x排序,y分治,z树状数组
/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int Tree[maxn],n,k;
int out[maxn];
void Add(int x,int val){
for(;x<=k;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
for(;x;x-=x&-x)ans += Tree[x];
return ans;
}
struct node{
int x,y,z;
int ans,w;
bool operator < (const node &T)const{
if(x != T.x)return x<T.x;
if(y != T.y)return y<T.y;
return z<T.z;
}
bool operator == (const node T)const{
return (x == T.x)&&(y == T.y)&&(z == T.z);
}
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r){
if(l == r)return ;
int mid = l+r>>1;
CDQ(l,mid),CDQ(mid+1,r);
int L = l,R = mid+1,cnt = l;
while(L<=mid && R<=r){
if(Qt[L].y<=Qt[R].y){
Add(Qt[L].z,Qt[L].w);
Tmp[cnt++] = Qt[L++];
}else{
Qt[R].ans += query(Qt[R].z);
Tmp[cnt++] = Qt[R++];
}
}
while(R<=r){
Qt[R].ans += query(Qt[R].z);
Tmp[cnt++] = Qt[R++];
}
for(int i=l;i<L;i++)Add(Qt[i].z,-Qt[i].w);
while(L<=mid)Tmp[cnt++] = Qt[L++];
for(int i=l;i<=r;i++)Qt[i] = Tmp[i];
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d%d%d",&Tmp[i].x,&Tmp[i].y,&Tmp[i].z);
sort(Tmp+1,Tmp+1+n);
int cnt = 0,pos = 1;
while(pos<=n){
Qt[++cnt] = Tmp[pos];
Qt[cnt].w = 1;
Qt[cnt].ans = 0;
while(pos<n && Tmp[pos] == Tmp[pos+1]){
Qt[cnt].w++;
pos++;
}
pos++;
}
CDQ(1,cnt);
for(int i=1;i<=cnt;i++)out[Qt[i].ans+Qt[i].w-1] += Qt[i].w;
for(int i=0;i<n;i++)printf("%d\n",out[i]);
return 0;
}
统计矩阵内点数(可带权)
/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int Tree[maxn],ans[maxn],w,n,cnt,tot;
void add(int x,int val){while(x<=w)Tree[x] += val,x+=x&-x;}
int query(int x,int ans = 0){while(x)ans += Tree[x],x-=x&-x;return ans;}
struct node{
int x,y,w;
int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r){
if(l == r)return;
int mid = l+r>>1;
CDQ(l,mid),CDQ(mid+1,r);
int L = l,R = mid+1,cnt = l;
while(L<=mid && R<=r){
if(Qt[L].x <= Qt[R].x){
if(!Qt[L].opt)add(Qt[L].y,Qt[L].w);
Tmp[cnt++] = Qt[L++];
}else{
if(Qt[R].opt == 1)ans[Qt[R].pos] -= query(Qt[R].w)-query(Qt[R].y-1);
if(Qt[R].opt == 2)ans[Qt[R].pos] += query(Qt[R].w)-query(Qt[R].y-1);
Tmp[cnt++] = Qt[R++];
}
}
while(R<=r){
if(Qt[R].opt == 1)ans[Qt[R].pos] -= query(Qt[R].w)-query(Qt[R].y-1);
if(Qt[R].opt == 2)ans[Qt[R].pos] += query(Qt[R].w)-query(Qt[R].y-1);
Tmp[cnt++] = Qt[R++];
}
for(int i=l;i<L;i++)if(!Qt[i].opt)add(Qt[i].y,-Qt[i].w);
while(L<=mid)Tmp[cnt++] = Qt[L++];
for(int i=l;i<=r;i++)Qt[i] = Tmp[i];
}
int main(){
freopen("locust.in","r",stdin);
freopen("locust.out","w",stdout);
scanf("%d%d",&w,&n);
for(int i=1,opt,x,y,z;i<=n;i++){
scanf("%d",&opt);
if(opt == 1){
scanf("%d%d%d",&x,&y,&z);
Qt[++cnt] = {x,y,z,0,0};
}else{
++tot;
scanf("%d%d%d%d",&x,&y,&z,&opt);
if(x>z)swap(x,z);
if(y>opt)swap(y,opt);
Qt[++cnt] = {x-1,y,opt,tot,1};
Qt[++cnt] = {z,y,opt,tot,2};
}
}
CDQ(1,cnt);
for(int i=1;i<=tot;i++)printf("%d\n",ans[i]);
return 0;
}
整体二分,静态区间第k小(主席树)
/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+7,inf = 1e9+7;
int Tree[maxn],n,m;
int ans[maxn];
void Add(int x,int val){
for(;x<=n;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
for(;x;x-=x&-x)ans += Tree[x];
return ans;
}
struct node{
int x,y,k;
int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r,int L,int R){
if(l>r || L>R)return;
if(l == r){
for(int i=L;i<=R;i++)if(Qt[i].opt){
ans[Qt[i].pos] = l;
}
return;
}
int mid = (l+r)>>1;
int cnl = L,cnr = R;
for(int i=L;i<=R;i++){
if(Qt[i].opt){
int sum = query(Qt[i].y)-query(Qt[i].x-1);
if(sum<Qt[i].k){
Qt[i].k -= sum,Tmp[cnr--] = Qt[i];
}else{
Tmp[cnl++] = Qt[i];
}
}else{
if(Qt[i].x<=mid){
Add(Qt[i].pos,1),Tmp[cnl++] = Qt[i];
}else{
Tmp[cnr--] = Qt[i];
}
}
}
for(int i=L;i<cnl;i++)if(!Tmp[i].opt)Add(Tmp[i].pos,-1);
for(int i=L;i<=R;i++){
Qt[i] = i<cnl?Tmp[i]:Tmp[R-i+cnl];
}
CDQ(l,mid,L,cnl-1),CDQ(mid+1,r,cnr+1,R);
}
int main(){
int Ml = inf,Mr = -inf;
scanf("%d%d",&n,&m);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
Qt[i] = {x,0,0,i,0};
Ml = Ml<x?Ml:x;
Mr = Mr>x?Mr:x;
}
for(int i=1,x,y,k;i<=m;i++){
scanf("%d%d%d",&x,&y,&k);
Qt[i+n] = {x,y,k,i,1};
}
CDQ(Ml,Mr,1,n+m);
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
整体二分,动态区间k小(带修主席树)
/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+7,inf = 1e9+7;
int Tree[maxn],n,m,a[maxn];
int ans[maxn],tot,cnt;
void Add(int x,int val){
for(;x<=n;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
for(;x;x-=x&-x)ans += Tree[x];
return ans;
}
struct node{
int x,y,k;
int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r,int L,int R){
if(l>r || L>R)return;
if(l == r){
for(int i=L;i<=R;i++)if(Qt[i].opt>0){
ans[Qt[i].pos] = l;
}
return;
}
int mid = (l+r)>>1;
int cnl = L,cnr = R;
for(int i=L;i<=R;i++){
if(Qt[i].opt>0){
int sum = query(Qt[i].y)-query(Qt[i].x-1);
if(sum<Qt[i].k){
Qt[i].k -= sum,Tmp[cnr--] = Qt[i];
}else{
Tmp[cnl++] = Qt[i];
}
}else{
if(Qt[i].x<=mid){
Add(Qt[i].pos,Qt[i].opt?-1:1);
Tmp[cnl++] = Qt[i];
}else{
Tmp[cnr--] = Qt[i];
}
}
}
for(int i=L;i<cnl;i++)if(Tmp[i].opt<=0)Add(Tmp[i].pos,Tmp[i].opt?1:-1);
for(int i=L;i<=R;i++){
Qt[i] = i<cnl?Tmp[i]:Tmp[R-i+cnl];
}
CDQ(l,mid,L,cnl-1),CDQ(mid+1,r,cnr+1,R);
}
char opt[10];
int main(){
int T;
scanf("%d",&T);
while(T--){
cnt = tot = 0;
int Ml = inf,Mr = -inf;
scanf("%d%d",&n,&m);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
a[i] = x;
Qt[++cnt] = {x,0,0,i,0};//insert
Ml = Ml<x?Ml:x;
Mr = Mr>x?Mr:x;
}
for(int i=1,x,y,k;i<=m;i++){
scanf("%s",opt);
if(opt[0] == 'Q'){
scanf("%d%d%d",&x,&y,&k);
Qt[++cnt] = {x,y,k,++tot,1};//ask
}else{
scanf("%d%d",&x,&y);
Qt[++cnt] = {a[x],0,0,x,-1};//delete
Qt[++cnt] = {y,0,0,x,0};//insert
a[x] = y;
}
}
CDQ(Ml,Mr,1,cnt);
for(int i=1;i<=tot;i++)printf("%d\n",ans[i]),ans[i] = 0;
}
return 0;
}