洛谷P3932浮游大陆的68号岛

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P3932浮游大陆的68号岛相关的知识,希望对你有一定的参考价值。

题目背景

大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg

浮游大陆的68号岛,位于浮游大陆的边境地带。平时很少有人造访。

岛上被浓厚的森林覆盖。

在这座边境地区不起眼的浮游岛上,建立着神秘的”兵器“管理仓库——妖精仓库。

题目描述

妖精仓库里生活着黄金妖精们,她们过着快乐,却随时准备着迎接死亡的生活。

换用更高尚的说法,是随时准备着为这个无药可救的世界献身。

然而孩子们的生活却总是无忧无虑的,幼体的黄金妖精们过着天真烂漫的生活,自然也无暇考虑什么拯救世界之类的重任。

 

有一天小妖精们又在做游戏。这个游戏是这样的。

妖精仓库的储物点可以看做在一个数轴上。每一个储物点会有一些东西,同时他们之间存在距离。

每次他们会选出一个小妖精,然后剩下的人找到区间[l,r][l,r]储物点的所有东西,清点完毕之后问她,把这个区间内所有储物点的东西运到另外一个仓库的代价是多少?

比如储物点i有x个东西,要运到储物点j,代价为

$x \times \mathrm{dist}( i , j )$

dist就是仓库间的距离。

当然啦,由于小妖精们不会算很大的数字,因此您的答案需要对19260817取模。

输入输出格式

输入格式:

 

第一行两个数表示n,mn,m

第二行n-1n?1个数,第ii个数表示第ii个储物点与第i+1i+1个储物点的距离

第三行nn个数,表示每个储物点的东西个数

之后mm行每行三个数x l r

表示查询要把区间[l,r][l,r]储物点的物品全部运到储物点x的花费

输出格式:

对于每个询问输出一个数表示答案

输入输出样例

输入样例#1:
5 5
2 3 4 5
1 2 3 4 5
1 1 5
3 1 5
2 3 3
3 3 3
1 5 5
输出样例#1:
125
72
9
0
70

说明

对于30%的数据,n , m \le 1000n,m1000

对于另外20%的数据,所有储物点间的距离都为1

对于另外20%的数据,所有储物点的物品数都为1

对于100%的数据 ,n , m \le 200000 ; a_i , b_i <= 2\cdot 10^9n,m≤200000;a  i ?  ,b  i ?  <=2?10  9

分析

我在考试的时候画呀画有时没有画出来,到最后写了一个线段树卡过去了。看题解才知道这题正解是前缀和。╮( ̄▽ ̄")╭还是本蒟蒻数学功底太差了,没有向数学模型去转化......

代码

正解:

 我要说一句 C++ mod自带大常数,在保证答案正确的情况下能少用就少用吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=200000+5;
const ll mod=19260817;
template<class T>
inline void read(T &x){
    x=0; char ch=getchar();
    while(ch<0||ch>9) ch=getchar();
    while(ch>=0&&ch<=9){x=(x<<1)+(x<<3)+ch-0;ch=getchar();}
}
int n,m;
ll sum1[maxn],sum2[maxn],dis[maxn];
int main(){
    read(n);read(m);
    for(int i=2;i<=n;++i) {
        read(dis[i]);
        dis[i]=(dis[i]+dis[i-1])%mod;
    }
    for(int i=1;i<=n;++i){    
        ll x;read(x); 
        sum1[i]=(sum1[i-1]+x*dis[i])%mod;
        sum2[i]=(sum2[i-1]+x)%mod;
    }
    int x,l,r; ll ans;
    for(int i=1;i<=m;++i){
        read(x);read(l);read(r);
        if(l>=x){
            ans=(sum1[r]-sum1[l-1]+mod)%mod;
            ans=(ans-((sum2[r]-sum2[l-1]+mod)*dis[x])%mod+mod)%mod;
        }else if(x>=r){
            ans=((sum2[r]-sum2[l-1]+mod)*dis[x])%mod;
            ans=(ans-(sum1[r]-sum1[l-1])+mod)%mod;
        }else if(x>l&&x<r){
            ans=((sum2[x-1]-sum2[l-1]+mod)*dis[x])%mod;
            ans=(ans-(sum1[x-1]-sum1[l-1])+mod)%mod;
            ans=(ans+sum1[r]-sum1[x]+mod)%mod;
            ans=(ans-((sum2[r]-sum2[x]+mod)*dis[x])%mod+mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

线段树

这是一种离线的做法,先与处理出来所有点都移动到第一个点,处理目标点为1的答案,然后将目标点向右移,关系式应该很好推。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson now<<1,l,mid
#define rson now<<1|1,mid+1,r
using namespace std;
typedef long long ll;
const int maxn=200000+5;
const ll mod=19260817;
template<class T>
inline void read(T &x){
    x=0; char ch=getchar();
    while(ch<0||ch>9) ch=getchar();
    while(ch>=0&&ch<=9){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}
int n,m;
ll dis[maxn],num[maxn],ans[maxn],tmp[maxn],s[maxn],c[maxn];
ll sum[maxn<<2],tag[maxn<<2],sum2[maxn<<2];
struct ask{
    int x,l,r,id;
    bool operator < (const ask &j) const{
        return x==j.x? r<j.r:x<j.x;
    }
}q[maxn];
inline void pushup(int now){
    sum[now]=(sum[now<<1]+sum[now<<1|1])%mod;
    sum2[now]=(sum2[now<<1]+sum2[now<<1|1])%mod;
}
inline void pushdown(int now){
    if(!tag[now]) return;
    int lc=now<<1,rc=now<<1|1;
    sum[lc]=(sum[lc]+tag[now]*sum2[lc])%mod;
    sum[rc]=(sum[rc]+tag[now]*sum2[rc])%mod;
    tag[lc]=(tag[lc]+tag[now])%mod;
    tag[rc]=(tag[rc]+tag[now])%mod;
    tag[now]=0;
}
void bt(int now,int l,int r){
    if(l==r){
        sum[now]=tmp[l]%mod;
        sum2[now]=num[l]%mod;
        return;
    }
    int mid=(l+r)>>1;
    bt(lson); bt(rson);
    pushup(now);
}
void update(int now,int l,int r,int x,int y,int k){
    if(x<=l&&r<=y){
        sum[now]=(sum[now]+k*sum2[now])%mod;
        tag[now]=(tag[now]+k)%mod;
        return;
    }
    pushdown(now);
    int mid=(l+r)>>1;
    if(x<=mid) update(lson,x,y,k);
    if(y>mid) update(rson,x,y,k);
    pushup(now);
}
ll query(int now,int l,int r,int x,int y){
    if(x<=l&&r<=y) return sum[now];
    pushdown(now);
    ll res=0; int mid=(l+r)>>1;
    if(x<=mid) res+=query(lson,x,y);
    if(y>mid) res=(res+query(rson,x,y))%mod;
    return res;
}
int main(){
    read(n);read(m);
    for(int i=2;i<=n;++i){
        read(dis[i]);
        dis[i]=(dis[i]+dis[i-1])%mod;
    }
    for(int i=1;i<=n;++i) read(num[i]);
    for(int i=1;i<=m;++i){
        read(q[i].x);read(q[i].l);read(q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1);
    int cur=1;
    for(int i=1;i<=n;++i){
        tmp[i]=((dis[i]-dis[0]+mod)*num[i])%mod;
        s[i]=(s[i-1]+tmp[i])%mod;
        while(q[cur].x==1&&q[cur].r==i){
            ans[q[cur].id]=(s[i]-s[q[cur].l-1]+mod)%mod;
            cur++;
        }
    }
    bt(1,1,n);
    for(int i=2;i<=n;++i){
        update(1,1,n,1,i-1,(dis[i]-dis[i-1]+mod)%mod);
        update(1,1,n,i,n,(dis[i-1]-dis[i]+mod)%mod);
        while(q[cur].x==i){
            ans[q[cur].id]=query(1,1,n,q[cur].l,q[cur].r);
            cur++;
        }
    }
    for(int i=1;i<=m;++i)
        printf("%lld\n",ans[i]);
}

 

以上是关于洛谷P3932浮游大陆的68号岛的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3932 浮游大陆的68号岛 题解

P3932 浮游大陆的68号岛

P3932 浮游大陆的68号岛

luogu P3932 浮游大陆的68号岛

[Luogu3932] 浮游大陆的68号岛

洛谷八连测R7nzhtl1477-我回来了