码迷,mamicode.com
首页 > 其他好文 > 详细

洛谷——P2781 传教

时间:2017-10-22 22:04:28      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:copy   lap   efi   搜索   div   bad   down   最小   输入格式   

P2781 传教

题目背景

写完暑假作业后,bx2k去找pear玩。pear表示他要去汉中传教,于是bx2k准备跟着去围观。

题目描述

pear把即将接受传教的人排成一行,每个人从左到右的编号为1-n。每个人有一个信仰值,一开始所有人的信仰值为0。接着pear会做以下两件事之一:

1.pear向连续的一段人群传教。具体来说,pear会使第l个人到第r个人之间的所有人的信仰值增加k。

2.pear想知道某一段人的信仰值之和来得知泉岭精神是否深入人心。具体来说,pear会问bx2k第l个人到第r个人之间所有人的信仰值之和。

身为一个泉岭精神的信徒,bx2k自然会帮pear来算。但是bx2k太笨了,根本不会算。于是他想找你来帮忙。

输入输出格式

输入格式:

 

第一行包含两个整数n,m。分别表示接受传教的人数以及pear的操作数。

接下来m行,每行包含若干个整数。若第一个整数为1,则代表pear在进行传教,这一行接下来会包含l,r,k三个整数。否则第一个整数为2,代表pear的一个询问,这一行接下来会包含l,r两个整数。

 

输出格式:

 

输出若干行,每行包含1个整数,表示pear询问的答案。行数为pear的询问数量。

 

输入输出样例

输入样例#1: 复制
5 5
2 1 2
1 4 4 2
1 2 4 7
1 4 5 6
2 3 4
输出样例#1: 复制
0
22

说明

【样例说明】

一开始所有人的信仰值都为0,所以答案为0。到第五个操作时,五个人的信仰值分别为0,7,7,15,6。则答案为7+15=22

【数据范围与约定】

对于1-3测试点,n,m<=10

对于4-5测试点,n,m<=10^3

对于6-8测试点,没有传教操作。

对于所有测试点,n<=10^9,m<=10^3,0<l<=n,0<r<=n,k<=10

 

 

搜索??

明明是线段树裸题好不好,哈哈,恭喜你,编译都过不了、、(数据范围10^9)

技术分享
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100000000
using namespace std;
int n,p,a,b,c,Q,ans;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x*f;
 } 
struct Tree
{
    int v,l,r,f;
}tree[N];
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(k<<1,l,mid); build(k<<1|1,mid+1,r);
    tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
}
void down(int k)
{
    tree[k<<1].f+=tree[k].f;
    tree[k<<1|1].f+=tree[k].f;
    tree[k<<1].v+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].f;
    tree[k<<1|1].v+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].f;
    tree[k].f=0;
}
void change(int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].v+=(tree[k].r-tree[k].l+1)*c;
        tree[k].f+=c;
        return ;
    }
    if(tree[k].f) down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(a<=mid) change(k<<1);
    if(b>mid) change(k<<1|1);
    tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
}
void ask(int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].v;
        return ;
    }
    if(tree[k].f) down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(a<=mid) ask(k<<1);
    if(b>mid) ask(k<<1|1);
}
int main()
{
    n=read();
    build(1,1,n);
    Q=read();
    while(Q--)
    {
        p=read(),ans=0;
        if(p==1) 
         a=read(),b=read(),c=read(),change(1);
        else
        {
            a=read(),b=read(),ask(1);
            printf("%d\n",ans);
        } 
    }
    return 0;
}
0分线段树(全部RE)

 

将近m^2的做法

我们可以发现m的范围很小,可以支持m^2的操作,我们在每次执行到一个查询操作的时候,枚举在这个操作之前的操作,判断这个操作过的区间是否与我们要查询的区间相交,如果相交的话,我们求出相交的那一部分,左端点为这两段区间左端点的最小值,右端点为这两段区间的最大值,然后我们用这段相交的区间的区间大小*修改的值累加起来即为最终答案

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
int n,m,p;
long long ans;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x*f;
 } 
struct Tree
{
    int l,r,v;
}tree[N];
void ask(int x,int y)
{
    for(int i=1;i<m;i++)
    {
        if(tree[i].l>y||tree[i].r<x) continue;
        ans+=1ll*(min(tree[i].r,y)-max(tree[i].l,x)+1)*tree[i].v;
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        p=read(),ans=0;
        if(p==1) 
          tree[i].l=read(),tree[i].r=read(),tree[i].v=read();
        else
        {
            tree[i].l=read(),tree[i].r=read();
            ask(tree[i].l,tree[i].r);
            printf("%lld\n",ans);
        } 
    }
    return 0;
}

 

洛谷——P2781 传教

标签:copy   lap   efi   搜索   div   bad   down   最小   输入格式   

原文地址:http://www.cnblogs.com/z360/p/7710774.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!