首页 > 其他分享 >P3755 [CQOI2017]老C的任务 题解

P3755 [CQOI2017]老C的任务 题解

时间:2022-08-25 11:56:27浏览次数:96  
标签:return int 题解 分治 mid cdq CQOI2017 P3755 CDQ

CDQ分治

对于这道题,可以参考 P4390 [BOI2007]Mokia 摩基亚 的做法,可以通过 CDQ 分治离线操作高效处理出答案(我常数大,不能体现出 CDQ 分治的优秀)。

可以发现,操作 11 和操作 22 分好了界限,于是我们只需要统计答案,不用再使用树状数组维护。

对于 CDQ 分治,我们可以先看一道例题(逆序对):

//这是很经典的二维偏序问题,满足下标和值的大小关系即可。
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);cdq(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){
        if(a[i]<=a[j])tmp[k++]=a[i++];
        else ans+=mid-i+1,tmp[k++]=a[j++];
    }
    while(i<=mid)tmp[k++]=a[i++];
    while(j<=r)tmp[k++]=a[j++];
    for(int i=l;i<=r;i++)a[i]=tmp[i];
}

很显然,本题也是一个二维偏序问题。对于询问 xx yy ,查询 \sum_{i=0}^x\sum_{j=0}^y val_{i,j}∑i=0x​∑j=0y​vali,j​ ,val_{i,j}vali,j​ 为点 (i,j)(i,j) 的值。

对于 ii 的贡献,我们只需要找到 x_i<x_j,y_i<y_jxi​<xj​,yi​<yj​ 对于每个数对,答案加上 ii 位置的权值,具体实现和逆序对相似。

先按照 xx 排个序,在分治算法中找到 y_i<y_jyi​<yj​ 的数对即可。

void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);cdq(mid+1,r);
    int i=l,j=mid+1,k=l,cnt=0;
    while(j<=r&&i<=mid){
        if(q[i].y<=q[j].y){
            if(q[i].typ==1)cnt+=q[i].a;//对于i,yj>yi,且y点有值,那么加上
            tmp[k++]=q[i++];
        }else{
            if(q[j].typ==2)q[j].a+=cnt;//如果q[j].y<q[i].y,那么j这个点的贡献加上之前累加的cnt,因为这里的i是上一次询问的i,没动过。
            tmp[k++]=q[j++];    
        }
    }
    while(i<=mid){//再次统计一遍,以免漏掉
        if(q[i].typ==1)cnt+=q[i].a;
        tmp[k++]=q[i++];
    }
    while(j<=r){
        if(q[j].typ==2)q[j].a+=cnt;
        tmp[k++]=q[j++];
    }
    for(int i=l;i<=r;i++)q[i]=tmp[i];//归并排序
}

最后按照询问的时间排序,运用差分知识统计一下矩阵和即可:

#include<cstdio>
#include<algorithm>
#define N 1919810
#define int long long
using namespace std;
int n,m,tot;
struct node{
    int x,y,typ,a,t;
}q[N],tmp[N];
bool cmp(node a,node b){
    if(a.x!=b.x)return a.x<b.x;
    else if(a.y!=b.y)return a.y<b.y;
    return a.typ<b.typ;
}
bool cmp2(node a,node b){return a.t<b.t;}
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);cdq(mid+1,r);
    int i=l,j=mid+1,k=l,cnt=0;
    while(j<=r&&i<=mid){
        if(q[i].y<=q[j].y){
            if(q[i].typ==1)cnt+=q[i].a;
            tmp[k++]=q[i++];
        }else{
            if(q[j].typ==2)q[j].a+=cnt;
            tmp[k++]=q[j++];    
        }
    }
    while(i<=mid){
        if(q[i].typ==1)cnt+=q[i].a;
        tmp[k++]=q[i++];
    }
    while(j<=r){
        if(q[j].typ==2)q[j].a+=cnt;
        tmp[k++]=q[j++];
    }
    for(int i=l;i<=r;i++)q[i]=tmp[i];
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)q[++tot].typ=1,q[tot].t=tot,scanf("%lld%lld%lld",&q[tot].x,&q[tot].y,&q[tot].a);
    for(int i=1;i<=m;i++){
        int x,y,xx,yy;
        scanf("%lld%lld%lld%lld",&x,&y,&xx,&yy);
        q[++tot].x=xx,q[tot].y=yy,q[tot].typ=2,q[tot].t=tot;
        q[++tot].x=x-1,q[tot].y=yy,q[tot].typ=2,q[tot].t=tot;
        q[++tot].x=xx,q[tot].y=y-1,q[tot].typ=2,q[tot].t=tot;
        q[++tot].x=x-1,q[tot].y=y-1,q[tot].typ=2,q[tot].t=tot;  
    }
    sort(q+1,q+tot+1,cmp);
    cdq(1,tot);
    sort(q+1,q+tot+1,cmp2);
    for(int i=n+1;i<=tot;i++){
        printf("%lld\n",q[i].a-q[i+1].a-q[i+2].a+q[i+3].a);
        i+=3;
    }
    return 0;
}
 

标签:return,int,题解,分治,mid,cdq,CQOI2017,P3755,CDQ
From: https://www.cnblogs.com/masida-hall-LZ/p/16623827.html

相关文章

  • CF1121B Mike and Children 题解
    题意翻译十分简洁,我说几点需要注意的。最多能选几个数?这是错的,要给出最多选出几对数。现在我们就珂以开始了。我的做法理论时间复杂度是 O(n^3)O(n3) 的暴力,但是因......
  • @RequestBody注解转对象中驼峰格式的参数无法接收到数据的问题解决方法
    1.问题:驼峰格式的参数传递到后端,@RequestBody注解标注的实体对象参数没有接收到对应的数据前端传参:执行结果:请求参数实体:importlombok.Data;/***请求参数*@author......
  • CSP 202006-1 202006-2 题解
    #202006-1线性分类器在坐标系中,我们可以考虑使用同一横坐标x值对应的y值来判断在直线的上方一侧还是在下方一侧。当然,如果不在坐标系中也可以统计点和直线的位置关系,这......
  • B3620 题解
    题目传送门\(\color{red}{see}\space\color{green}{in}\space\color{blue}{my}\space\color{purple}{blog}\)小学生又双叒叕来写题解啦!这题是\(x\)进制转\(10\)......
  • CF1646B 题解
    题目传送门\(\color{red}{see}\space\color{green}{in}\space\color{blue}{my}\space\color{purple}{blog}\)看到题解里没有用双指针往中间靠的写法的,果断来一发。思......
  • CF1624C 题解
    题目传送门\(\color{red}{see}\space\color{green}{in}\space\color{blue}{my}\space\color{purple}{blog}\)小学生又双叒叕来写题解啦!这题还是很简单的,甚至不需要像......
  • CF1617B 题解
    题目传送门\(\color{red}{see}\space\color{green}{in}\space\color{blue}{my}\space\color{purple}{blog}\)小学生又双叒叕来写题解啦!其他题解的代码都是\(O(1)\)......
  • CF402A 题解
    题目传送门\(\color{red}{see}\space\color{blue}{in}\space\color{green}{my}\space\color{purple}{blog}\)小学生又双叒叕来写题解啦!看到其他题解描述得并不清晰,我......
  • AT4894 题解
    题目传送门小学生又双叒叕来写题解啦!翻了一下大家的思路,都用了数组,其实根本不用,可以一边读入一边判断。由于只需考虑前后两个数,所以只用两个变量就能实现滚动数组。若......
  • AT4783 题解
    题目传送门小学生又双叒叕来写题解啦!这题的关键就是贪心。看到N的范围,瞬间明白可能要排序。所以我们靠着排序来想。我们来思考一下怎样安排顺序。对于两个时间限......