2018陕西省赛K题[watermelon_planting]

题意:有一个序列a[],描述的是另一个序列ans[]每个位置单位时间的增量。每个单位时间每个位置都会增加一个单位对应增量。时间总长m,每个单位时间包含有两种操作中的一个:1.询问ans[]在[l,r]区间的和;2.修改:a[]在[l,r]区间+1,即[l,r]区间的ans[]增量+1,a[i], n,m?≤?10^5

题解:当时脑抽没想出来,现在觉得好简单。。。考虑对每个位置,维护一个关于时间的一次函数y=a*x+b,y:是这个位置的答案,x:是时间,然后就维护两个系数a,b就可以了。维护的方法就是开两颗线段树分别维护a,b,这就是个裸的区间加,区间求和。位置i系数的表达式:a = (ai + 修改次数),b = - (修改的时间和)。随机跑了跑没啥大问题,发现问题欢迎评论区指出。(大概一辈子都是桶排选手吧。)

#include <bits/stdc++.h>
typedef long long ll;
const int N = 1e5 + 100;
using namespace std;
int n,m;
ll a[N];
struct seg{int l,r;ll sum,tag;}tree[2][N<<2];
void push_up(int p,seg* tree) {
    tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
}
void push_down(int p,seg* tree) {
    if(tree[p].tag) {
        tree[p<<1].sum += 1LL*(tree[p<<1].r - tree[p<<1].l + 1)*tree[p].tag;
        tree[p<<1|1].sum += 1LL*(tree[p<<1|1].r - tree[p<<1|1].l + 1)*tree[p].tag;
        tree[p<<1].tag += tree[p].tag;
        tree[p<<1|1].tag += tree[p].tag;
        tree[p].tag = 0;
    }
}
void build(int p, int l, int r, seg* tree) {
    tree[p].l = l; tree[p].r = r;
    tree[p].sum = tree[p].tag = 0;
    if(l == r) {
        tree[p].sum = a[l]; return;
    }
    int mid = (l + r) >> 1;
    build(p<<1, l, mid, tree), build(p<<1|1, mid+1, r, tree);
    push_up(p, tree);
}
void buildb(int p, int l, int r, seg* tree) {
    tree[p].l = l; tree[p].r = r;
    tree[p].sum = tree[p].tag = 0;
    if(l == r) return;
    int mid = (l + r) >> 1;
    buildb(p<<1, l, mid, tree), buildb(p<<1|1, mid+1, r, tree);
    push_up(p, tree);
}
void add(int p, int l, int r, ll x,seg* tree) {
    if(tree[p].l == l && tree[p].r ==r) {
        tree[p].sum += 1LL*(r-l+1)*x;
        tree[p].tag += x;
        return;
    }
    int mid = (tree[p].l + tree[p].r) >> 1;
    push_down(p, tree);
    if(r <= mid) add(p<<1, l, r, x, tree);
    else if(l > mid) add(p<<1|1, l, r, x, tree);
    else add(p<<1, l, mid, x, tree), add(p<<1|1, mid+1, r, x, tree);
    push_up(p, tree);
}
ll ask(int p, int l, int r,seg* tree) {
    if(tree[p].l == l && tree[p].r == r) return tree[p].sum;
    push_down(p, tree);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if(r <= mid) return ask(p<<1, l, r, tree);
    else if(l > mid) return ask(p<<1|1, l, r, tree);
    else return ask(p<<1, l, mid, tree) + ask(p<<1|1, mid+1, r, tree);
}
//ll ans[N];
//void update(int l,int r){
//    for(int i=1;i<=n;++i)ans[i]+=a[i];
//    for(int i=l;i<=r;++i)++a[i];
//}
//ll ask2(int l,int r){ll res=0;
//    for(int i=1;i<=n;++i)ans[i]+=a[i];
//    for(int i=l;i<=r;++i)res+=ans[i];
//    return res;
//}
int main() {
    while(scanf("%d",&n)) {
        for(int i=1;i<=n;++i)scanf("%lld",&a[i]);//,ans[i]=0;
        build(1,1,n,tree[0]);
        buildb(1,1,n,tree[1]);
        scanf("%d",&m);
        for(int i=1;i<=m;++i) {char opt;int l,r;
            scanf(" %c %d %d",&opt,&l,&r);
            //opt=rand()%2;l=rand()%n+1,r=rand()%n+1;if(l>r)swap(l,r);
            //printf("%d : [%d,%d]\n",opt,l,r);
            if(opt==‘Q‘){
                ll ans = ask(1,l,r,tree[0])*i-ask(1,l,r,tree[1]);
                //ll ans2=ask2(l,r);
                printf("%lld\n",ans);
//                if(ans!=ans2){
//                    printf("_______________________\n");
//                }
            }
            else {
                add(1,l,r,1,tree[0]);
                add(1,l,r,i,tree[1]);
//                update(l,r);
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/RRRR-wys/p/9074789.html

时间: 2024-08-13 16:10:29

2018陕西省赛K题[watermelon_planting]的相关文章

hdu5080:几何+polya计数(鞍山区域赛K题)

/* 鞍山区域赛的K题..当时比赛都没来得及看(反正看了也不会) 学了polya定理之后就赶紧跑来补这个题.. 由于几何比较烂写了又丑又长的代码,还debug了很久.. 比较感动的是竟然1Y了.. */ 题目大意: 给定一些点,某些点上有边,问用k种颜色染色的等价类有多少种 思路: 由于坐标是整数..只有可能旋转90,180,270才能得到置换 且图形必须为中心对称图形 先用几何方法找出对称中心 然后旋转,找是否出现置换... 由于点数只有50,几何预处理这一部分可以很暴力无脑的写..各种判断相

ZOJ 3879 Capture the Flag 15年浙江省赛K题

每年省赛必有的一道模拟题,描述都是非常的长,题目都是蛮好写的... sigh... 比赛的时候没有写出这道题目 :( 题意:首先输入4个数,n,q,p,c代表有n个队伍,q个服务器,每支队伍的初始分数p, 还有c次操作对于每次操作,首先输入一个k,代表k次攻击每次攻击有三个数,a,b,c, 代表a通过c服务器成功的攻击了b对于每次成功的攻击,b会失去n-1分, 这n-1分会平分给通过同一服务器攻击b的几支队伍然后是q行,每行n个数, 分别代表1~n是否成功维护了,1为成功,0为不成功不成功的队伍

2018湖南省赛B题“2018”

题面懒得敲了,反正看这篇博客的肯定知道题面. 比赛时想按约数的一些性质分情况讨论出公式然后在合并,结果单考虑矩阵里出现2018和1009(与2互质,1009出现次数等于2)出现的情况就写了一长串公式,还推了很久.在考虑1出现的综合情况就直接GG了.. 然后想到打表,奈何队友卡H题很久,最终因时间原因放弃来做B的时候已经冷静不下来了,没能打表成功,于是今天决定补一手打表. 我首先敲了dfs暴搜二维数组的,然后类比的(找了半天BUG)终于成功打出来了..还是要好好练练打表,比赛卡这样的题真难受. 1

HDU 5122 K.Bro Sorting(2014北京区域赛现场赛K题 模拟)

这题定义了一种新的排序算法,就是把一串序列中的一个数,如果它右边的数比它小 则可以往右边移动,直到它右边的数字比它大为止. 易得,如果来模拟就是O(n^2)的效率,肯定不行 想了一想,这个问题可以被转化成 求这一串序列当中每个元素,它的右边是否存在小于它的数字,如果存在,则++ans 一开始没想到诶= = 不应该不应该 1 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler 2 #include <std

hdu 5137 去掉一个点 使得最短路最大(2014广州区域赛K题)

题意:从2~n-1这几个点中任意去掉一个点,使得从1到n的最短路径最大,如果任意去掉一个点1~n无通路输出Inf. Sample Input4 51 2 31 3 71 4 502 3 43 4 23 21 2 302 3 100 0 Sample Output50Inf 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 #

ZOJ 3879 Capture the Flag (浙江省省赛K题+模拟)

题目链接:ZOJ 3879 Capture the Flag 题意:给出n支队伍互相攻击服务器,有以下规则: 1.如果A队的服务器1被B队攻击成功,A队将失去n-1点分数,这n-1点分数会平分给成功攻击A队的服务器1的其他队伍. eg: 共4个队 A B 1 C B 1 此时A队和C队都获得1.5(3/2)分,B队失去3分 2.如果一个队不能维护好他们的服务器,该队将失去n-1分,这n-1分平分给其他能维护好服务器的队伍. eg: 1 1 0 1 0 1 1 1 针对服务器1(即第一行),只有C

hdu 4463 有一条边必须加上 (2012杭州区域赛K题)

耐克店 和 苹果店必须相连 Sample Input42 30 01 00 -1 1 -10 Sample Output3.41 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <cmath> 6 # define LL long long 7 using namespace std ; 8

HDU5137 How Many Maos Does the Guanxi Worth (13广州现场赛K题 )--最短路问题

链接:click here 题意:从2~n-1这几个点中任意去掉一个点,使得从1到n的最短路径最大,如果任意去掉一个点1~n无通路输出Inf. 去年这道题现场是队友1A过的,感觉好NB,当时还不会最短路问题,只是脑子里大概有这么个印象,做了之发现数据比较水,今天看了一下Dijkstra 和Floyd,用两种算法实现了一下: 题目描述有点长,但是搞清楚了,就很容易了,因为数据实在很水,算是最短路入门训练的一道题了 Dijkstra 算法 (1)令S={源点s + 已经确定了最短路径的顶点vi} (

2018山东省赛补题

题目链接 https://www.nowcoder.com/acm/contest/123/E 题解 https://www.cnblogs.com/Rubbishes/p/9074460.html #include <bits/stdc++.h> using namespace std; const int MAXN=1000005; int cnt[MAXN]; int main() { int t; while(~scanf("%d",&t)) { while