来自HQ的满满的恶意

题意:
你有一个初始序列全为0,下面有两种操作。
1.[l,r]区间加x^a。
2.[l,r]询问:f[x] = l~r多项式之和。求一个最大的p使得:
指数( >= p)的项总数 <= q,其中q已知,并且求出指数大于等于p的项的总数。
强制在线。
Hint:
题目背景和题意是分开的,题目背景非常长。
题目背景最后一句话:小强和阿米巴是好朋友、、、
虽然多项式加起来了。
可是。
多项式不合并。
我报警了
多项式不合并!!!
然后我们来研(tu)究 (cao)一下题解:
外层权值线段树表示:
指数在[l,r]区间的内层线段树(数的个数)。
内层下标线段树表示:
[l,r]之间一共有几个项使得指数在外层范围内。
那么我们一旦求了:
外层权值线段树[a,b]中内层为[l,r]的值
也就意味着:我们求得序列[l,r]中,指数在[a,b]之间的项的个数。
应对两个操作如下:
1.到外层线段树[q,q]然后在内层[l,r]里面开搞。
2.到外层线段树[q,R]里面,判断一下内层[l,r]的和是否小于q,如果小于,那么答案加上右边子树的和,然后到左子树继续询问,如果大于,那么跑到右子树继续,p就是你所在的外层线段树+1。
Orz hzt

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for (int i = pos[x]; i; i = g[i].nex)
#define u t[x]
#define Lc t[ u.lc ]
#define Rc t[ u.rc ]
using namespace std;
typedef long long LL;
typedef double DB;
const int N = 210000, M = 1000000;
int n, Q, tz = 4 * M, ans, ql, qr;
LL q, now, qz;
struct Seg_Tree {
    struct Seg_node { int lc, rc, lz; LL s; } t[N * 200];
    inline void PD(int x, int l) {
        if (!u.lz) return ;
        if (!u.lc) u.lc = ++ tz; if (!u.rc) u.rc = ++ tz;
        Lc.lz += u.lz, Rc.lz += u.lz, u.s += l * (LL)u.lz, u.lz = 0;
    }
    inline void Upd(int x) { u.s = Lc.s + Rc.s; }
    void Add(int &x, int l, int r) {
        if (!x) x = ++ tz; // cout << l <<" "<<r<<endl;
        PD(x, r - l + 1);
        if (ql > r || qr < l) return ;
        if (ql <= l && r <= qr) { u.lz ++, PD(x, r - l + 1); return ; }
        int mid = l + r >> 1;
        Add(u.lc, l, mid); Add(u.rc, mid + 1, r);
        Upd(x);
    }
    inline void Find(int x, int l, int r) {
        if (!x || ql > r || qr < l) return ;
        PD(x, r - l + 1);
        if (ql <= l && r <= qr) { qz += u.s; return ; }
        int mid = l + r >> 1;
        Find(u.lc, l, mid); Find(u.rc, mid + 1, r);
    }
}Seg;
void Add(int x, int l, int r) {
    Seg.Add(x, 1, n);
    if (l == r) return ;
    int mid = l + r >> 1;
    if (q <= mid) Add(x * 2, l, mid); 
    else Add(x * 2 + 1, mid + 1, r);
}
void Qry(int x, int l, int r) {
    if (l == r) { printf("%d %d\n", ans = l + 1, now); return ; }
    int mid = l + r >> 1;
    // cout << mid + 1<<" "<<r<<endl;
    qz = 0, Seg.Find(x * 2 + 1, 1, n);  //cout << qz << endl;
    if (now + qz > q) Qry(x * 2 + 1, mid + 1, r);
    else now += qz, Qry(x * 2, l, mid);
}
int main()
{
    scanf ("%d%d", &n, &Q);
    Rep(i, 1, n) { int x; scanf ("%d", &x); }
    while (Q --) {
        int ty;
        scanf ("%d%d%d%lld", &ty, &ql, &qr, &q);
        if (!ty) q ^= ans, Add(1, 0, M);
        else now = 0, Qry(1, 0, M);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值