看了几天cdq分治,刚看的时候感觉这样做是对的,但是又不知道为啥是对的,只是凭感觉在写。
后来再慢慢看就明白了。
cdq分治是为了降低维度,使原来的问题变得简单。通常可以顶替复杂的数据结构。
使用cdq分治的条件:
1.原问题可以转化为多维偏序问题。
2.修改相互独立。
3.题目允许离线。
其实归并排序求逆序对的过程就是一个简单的cdq分治。
一个简单的cdq分治的运用场景:
1。将某个位置上的值加上x
2。查询区间的和。
我们可以转化为二维偏序问题,第一维为时间,第二维为x坐标。
对于一个查询,我们要求的就是小于当前时间的&&x坐标小于当前查询坐标的值。
每次只统计左区间修改对右区间查询的影响。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x3f3f3f3f
#define LL long long
#define fir first
#define sec second
#define lson rt<<1
#define rson rt<<1|1
#define sq(x) (x)*(x)
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
using namespace std;
#define N 5000005
#define maxn 2000005
struct node
{
int type,val,id;
int qid;
friend bool operator <(node x,node y)
{
if(x.id!=y.id)return x.id<y.id;
else return x.type<y.type;
}
}q[N],q1[N];
LL ou[N];
int tot;
void add(int type,int id,int val,int qid)
{
q[tot].type=type;
q[tot].id=id;
q[tot].val=val;
q[tot].qid=qid;
tot++;
}
void cdq(int l,int r)
{
if(l==r)return ;
int m=(l+r)>>1;
cdq(l,m);
cdq(m+1,r);
LL sum=0;
int L=l;
int R=m+1;
int now=l;
while(L<=m&&R<=r)
{
if(q[L]<q[R])
{
if(q[L].type==1)sum+=q[L].val;
q1[now++]=q[L++];
}
else
{
if(q[R].type==2)ou[q[R].qid]-=sum;
if(q[R].type==3)ou[q[R].qid]+=sum;
q1[now++]=q[R++];
}
}
while(L<=m)
{
if(q[L].type==1)sum+=q[L].val;
q1[now++]=q[L++];
}
while(R<=r)
{
if(q[R].type==2)ou[q[R].qid]-=sum;
if(q[R].type==3)ou[q[R].qid]+=sum;
q1[now++]=q[R++];
}
rep(i,l,r)q[i]=q1[i];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int tmp;
tot=1;
rep(i,1,n)sca(tmp),add(1,i,tmp,0);
int qid=1;
rep(i,1,m)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==1) add(1,y,z,0);
else add(2,y-1,0,qid),add(3,z,0,qid),qid++;
}
cdq(1,tot-1);
rep(i,1,qid-1)printf("%lld\n",ou[i]);
}