初学cdq分治,推荐:__stdcall,讲的很详细很清楚,cdq分治解决离线问题特别方便,拿一个树状数组的模板题入门cdq分治,洛谷 P3374 ,点修改求区间和,先将每次操作存起来,每次查询 l r 的和,分成两次操作:查询 l-1 的前缀和和 r 的前缀和,特别标记,前面一次是减法,后面一次是加法, 并且标记这是第几次操作即这两次操作属于哪个答案的操作,然后根据操作的位置进行归并排序,每次把两个区间合并,由于右边区间的修改操作对右区间的查询操作贡献已经算完,只要统计左边区间的修改操作造成的前缀和对右区间的查询操作贡献就可以了,模拟一下归并排序就很容易懂了。
p3374代码:
#include<cstdio>
typedef long long ll;
const int maxn=5e5+10;
struct Query
{
int type,idx,val;
bool operator<(const Query& rhs)const
{
if(idx==rhs.idx)
return type<rhs.type;
return idx<rhs.idx;
}
}Q[maxn*3],tmp[maxn*3];
int tot=0,cnt=0;
ll ans[maxn];
void cdq(int l,int r)
{
if(r==l)return;
int m=(l+r)/2;
cdq(l,m);cdq(m+1,r);
ll sum=0;
int p=l,q=m+1,o=0;
while(p<=m&&q<=r)
if(Q[p]<Q[q])
{
if(Q[p].type==1)sum+=Q[p].val;
tmp[o++]=Q[p++];
}
else
{
if(Q[q].type==2)ans[Q[q].val]-=sum;
else if(Q[q].type==3)ans[Q[q].val]+=sum;
tmp[o++]=Q[q++];
}
while(p<=m)tmp[o++]=Q[p++];
while(q<=r)
{
if(Q[q].type==2)ans[Q[q].val]-=sum;
else if(Q[q].type==3)ans[Q[q].val]+=sum;
tmp[o++]=Q[q++];
}
for(int i=0;i<o;i++)
Q[l+i]=tmp[i];
}
int main()
{
int n,m,x,l,r;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&Q[++cnt].val);
Q[cnt].type=1,Q[cnt].idx=i;
}
while(m--)
{
scanf("%d",&Q[++cnt].type);
if(Q[cnt].type==1)
scanf("%d%d",&Q[cnt].idx,&Q[cnt].val);
else
{
scanf("%d%d",&l,&r);
Q[cnt].idx=l-1,Q[cnt].val=++tot;
Q[++cnt].type=3,Q[cnt].idx=r,Q[cnt].val=tot;
}
}
cdq(1,cnt);
for(int i=1;i<=tot;i++)printf("%lld\n",ans[i]);
}
Bubble Cup 11 - Finals [Online Mirror, Div. 2] A. AI robots
这个题可以先将每个机器人的可见范围 r 从小到大排序,这样如果左区间的机器人能看到右区间的机器人,那么右区间机器人肯定能看到左区间的,减少了考虑的因素,接下来对机器人按照q值归并排序,对于左区间每个机器人,将右区间所有q值与之相差<=k的机器人的x坐标插入树状数组,然后查询区间 x-r r+r的和即可,x和r分别代表左区间该机器人的坐标和可见范围。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct Query
{
int x,r,q,X,L,R;
bool operator<(const Query& rhs)const
{
return r<rhs.r;
}
}Q[maxn];
int n,k,sz=0,c[maxn*3],a[maxn*3];
ll ans=0;
int low(int x)
{
return x&(-x);
}
void update(int x,int v)
{
while(x<=sz)
{
c[x]+=v;
x+=low(x);
}
}
ll query(int x)
{
if(x<=0)return 0;
ll res=0;
while(x)
{
res+=c[x];
x-=low(x);
}
return res;
}
bool cmp(Query t1,Query t2)
{
return t1.q<t2.q;
}
void cdq(int l,int r)
{
if(l==r)return;
int m=(l+r)/2;
cdq(l,m),cdq(m+1,r);
int p=m+1,q=m+1;
for(int i=l;i<=m;i++)
{
while(q<=r&&Q[q].q<=Q[i].q+k)
update(Q[q].X,1),q++;
while(p<=r&&Q[p].q<Q[i].q-k)
update(Q[p].X,-1),p++;
ans+=query(Q[i].R)-query(Q[i].L-1);
}
for(int i=p;i<q;i++)update(Q[i].X,-1);
inplace_merge(Q+l,Q+m+1,Q+r+1,cmp);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&Q[i].x,&Q[i].r,&Q[i].q);
a[++sz]=Q[i].x-Q[i].r;
a[++sz]=Q[i].x;
a[++sz]=Q[i].x+Q[i].r;
}
sort(a+1,a+1+sz);
sz=unique(a+1,a+1+sz)-a-1;
for(int i=1;i<=n;i++)
{
Q[i].X=lower_bound(a+1,a+1+sz,Q[i].x)-a;
Q[i].L=lower_bound(a+1,a+1+sz,Q[i].x-Q[i].r)-a;
Q[i].R=lower_bound(a+1,a+1+sz,Q[i].x+Q[i].r)-a;
}
sort(Q+1,Q+1+n);
cdq(1,n);
printf("%I64d\n",ans);
}