码迷,mamicode.com
首页 > Web开发 > 详细

[题解] [JSOI2013] 奇怪的计算器

时间:2020-02-11 20:50:02      阅读:77      评论:0      收藏:0      [点我收藏+]

标签:uil   com   href   计算   down   scanf   geo   turn   bool   

题面

题解

我们发现经过若干次操作后这些数的相对大小都不会变

排序之后, 就只有一段前缀改为 L , 或一段后缀改为 R 了

考虑这样一个函数
\[ \displaystyle\\f(a_1, a_2, a_3) = a_1 * c_i + a_2*a_i + a_3 \]
其中 \(c_i\) 代表 \(i\) 这个位置现在的数, \(a_i\) 代表 \(i\) 这个位置原来的数

那么每次操作都可以看做加这个函数

  • \(k\) , 乘上\(f(1, 0, k)\)
  • \(k\) , 乘上 \(f(1, 0, -k)\)
  • \(k\) , 乘上 \(f(k, 0, 0)\)
  • \(@k\) , 乘上 \(f(1, k, 0)\)

线段树维护一下就好了

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 100005;
typedef long long ll; 
using namespace std;

int m, L, R, n, op[N], ans[N], num[N]; 
char s[104]; 
struct node
{
    int v, id;
    bool operator < (const node &p) const
    {
        return v < p.v; 
    }
} a[N];
struct Tree { ll mn, mx, p1, p2, p3; } t[N << 2]; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

void pushup(int p) { t[p].mn = t[p << 1].mn, t[p].mx = t[p << 1 | 1].mx; }

void pushtag(int p, int l, int r, ll p1, ll p2, ll p3)
{
    t[p].p1 *= p1, t[p].p2 = t[p].p2 * p1 + p2, t[p].p3 = t[p].p3 * p1 + p3;
    t[p].mn = t[p].mn * p1 + p2 * a[l].v + p3;
    t[p].mx = t[p].mx * p1 + p2 * a[r].v + p3; 
}

void pushdown(int p, int l, int r)
{
    if(t[p].p1 != 1 || t[p].p2 || t[p].p3)
    {
    int mid = (l + r) >> 1; 
    pushtag(p << 1, l, mid, t[p].p1, t[p].p2, t[p].p3);
    pushtag(p << 1 | 1, mid + 1, r, t[p].p1, t[p].p2, t[p].p3);
    t[p].p1 = 1, t[p].p2 = 0, t[p].p3 = 0; 
    }
}

void build(int p, int l, int r)
{
    t[p].p1 = 1; 
    if(l == r) return (void) (t[p].mn = t[p].mx = a[l].v); 
    int mid = (l + r) >> 1; 
    build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
    pushup(p); 
}

void modifymn(int p, int l, int r)
{
    if(l == r) return pushtag(p, l, r, 0, 0, L);
    pushdown(p, l, r);
    int mid = (l + r) >> 1;
    if(t[p << 1 | 1].mn < L)
    pushtag(p << 1, l, mid, 0, 0, L), modifymn(p << 1 | 1, mid + 1, r);
    else modifymn(p << 1, l, mid);
    pushup(p); 
}

void modifymx(int p, int l, int r)
{
    if(l == r) return pushtag(p, l, r, 0, 0, R);
    pushdown(p, l, r);
    int mid = (l + r) >> 1;
    if(t[p << 1].mx > R)
    pushtag(p << 1 | 1, mid + 1, r, 0, 0, R), modifymx(p << 1, l, mid);
    else modifymx(p << 1 | 1, mid + 1, r);
    pushup(p); 
}

void query(int p, int l, int r)
{
    if(l == r) return (void) (ans[a[l].id] = t[p].mn);
    pushdown(p, l, r);
    int mid = (l + r) >> 1;
    query(p << 1, l, mid), query(p << 1 | 1, mid + 1, r);
    pushup(p); 
}

int main()
{
    m = read <int> (), L = read <int> (), R = read <int> ();
    for(int i = 1; i <= m; i++)
    {
    scanf("%s", s + 1), num[i] = read <int> (); 
    if(s[1] == '+') op[i] = 1;
    else if(s[1] == '-') op[i] = 1, num[i] = -num[i];
    else if(s[1] == '*') op[i] = 2;
    else op[i] = 3; 
    }
    n = read <int> ();
    for(int i = 1; i <= n; i++) a[i].v = read <int> (), a[i].id = i;
    sort(a + 1, a + n + 1), build(1, 1, n); 
    for(int i = 1; i <= m; i++)
    {
    if(op[i] == 1) pushtag(1, 1, n, 1, 0, num[i]);
    else if(op[i] == 2) pushtag(1, 1, n, num[i], 0, 0);
    else if(op[i] == 3) pushtag(1, 1, n, 1, num[i], 0);
    if(t[1].mn < L) modifymn(1, 1, n);
    if(t[1].mx > R) modifymx(1, 1, n); 
    }
    query(1, 1, n);
    for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); 
    return 0; 
}

[题解] [JSOI2013] 奇怪的计算器

标签:uil   com   href   计算   down   scanf   geo   turn   bool   

原文地址:https://www.cnblogs.com/ztlztl/p/12296619.html

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