bzoj4889

http://www.lydsy.com/JudgeOnline/problem.php?id=4889

人傻常数大 bzoj上跑不过 洛谷上能过两到三个点

我写的是树套树啊 怎么跑的比分块还慢

每次可以发现交换两个点 只对他们中间的点有影响 所以我们只用计算比x小的数的和 比x大的数的和 比y小的数的和 比y大的数的和 然后计算一下就可以了 很明显可以用各种数据结构维护

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4000010;
const ll mod = 1000000007;
int n, m, cnt;
ll ans;
int q[N];
inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < ‘0‘ || c > ‘9‘)
    {
        if(c == ‘-‘) f = -1;
        c = getchar();
    }
    while(c >= ‘0‘ && c <= ‘9‘)
    {
        x = x * 10 + c - ‘0‘;
        c = getchar();
    }
    return x * f;
}
struct BIT {
    ll tree[N], count[N];
    int lowbit(int i)
    {
        return i & (-i);
    }
    void update(int pos, ll delta)
    {
        for(int i = pos; i <= 50001; i += lowbit(i))
        {
            tree[i] = (tree[i] + delta) % mod;
            ++count[i];
        }
    }
    ll query(int pos, ll delta)
    {
        ll ret1 = 0, ret2 = 0;
        for(int i = pos; i; i -= lowbit(i))
        {
            ret1 = (ret1 + tree[i]) % mod;
            ret2 += count[i];
        }
        ret1 = (ret1 + ret2 * delta) % mod;
        return ret1;
    }
} B;
struct data {
    int a;
    ll v;
} tree[N], a[N];
namespace splaytree
{
    int fa[N], child[N][2], root[N];
    ll size[N], num[N], sum[N];
    void update(int x)
    {
        size[x] = num[x] + size[child[x][0]] + size[child[x][1]];
        sum[x] = (tree[x].v * num[x] + sum[child[x][0]] + sum[child[x][1]]) % mod;
    }
    void zig(int x)
    {
        int y = fa[x];
        fa[x] = fa[y];
        child[fa[x]][child[fa[x]][1] == y] = x;
        child[y][0] = child[x][1];
        fa[child[x][1]] = y;
        fa[y] = x;
        child[x][1] = y;
        update(y);
        update(x);
    }
    void zag(int x)
    {
        int y = fa[x];
        fa[x] = fa[y];
        child[fa[x]][child[fa[x]][1] == y] = x;
        child[y][1] = child[x][0];
        fa[child[x][0]] = y;
        fa[y] = x;
        child[x][0] = y;
        update(y);
        update(x);
    }
    void splay(int x, int t, int pos)
    {
        while(fa[x] != t)
        {
            int y = fa[x], z = fa[y];
            if(z == t)
            {
                child[y][0] == x ? zig(x) : zag(x);
                break;
            }
            else if(y == child[z][0] && x == child[y][0]) { zig(y); zig(x); }
            else if(y == child[z][1] && x == child[y][1]) { zag(y); zag(x); }
            else if(y == child[z][0] && x == child[y][1]) { zag(x); zig(x); }
            else if(y == child[z][1] && x == child[y][0]) { zig(x); zag(x); }
        }
        if(!t) root[pos] = x;
        update(root[pos]);
    }
    void up(int x)
    {
        while(x)
        {
            update(x);
            x = fa[x];
        }
    }
    ll getbig(int pos, data &k)
    {
        int now = root[pos];
        ll ret = 0;
        while(now)
        {
            if(tree[now].a > k.a)
            {
                ret = (ret + k.v + tree[now].v) % mod;
                ret = (ret + k.v * size[child[now][1]] +
                       sum[child[now][1]]) % mod;
                now = child[now][0];
            }
            else now = child[now][1];
        }
        return ret;
    }
    ll getsmall(int pos, data &k)
    {
        int now = root[pos];
        ll ret = 0;
        while(now)
        {
            if(tree[now].a < k.a)
            {
                ret = (ret + k.v + tree[now].v) % mod;
                ret = (ret + k.v * size[child[now][0]] +
                       sum[child[now][0]]) % mod;
                now = child[now][1];
            }
            else now = child[now][0];
        }
        return ret;
    }
    int find(int x, data &k)
    {
        for(x = root[x]; x; x = child[x][k.a > tree[x].a])
            if(tree[x].a == k.a) return x;
    }
    void del(int pos, int x)
    {
        splay(x, 0, pos);
        if(num[x] > 1)
        {
            --num[x];
            update(x);
            return;
        }
        if(child[x][0] * child[x][1] == 0)
        {
            root[pos] = child[x][0] + child[x][1];
            fa[root[pos]] = 0;
            child[x][0] = child[x][1] = fa[x] = 0;
            return;
        }
        int now = child[x][1];
        while(child[now][0]) now = child[now][0];
        fa[child[x][0]] = now;
        child[now][0] = child[x][0];
        root[pos] = child[x][1];
        fa[root[pos]] = 0;
        up(child[x][0]);
        child[x][0] = child[x][1] = num[x] = size[x]
        = fa[x] = 0;
        splay(now, 0, pos);
    }
    void insert(int pos, data &k)
    {
        int now = root[pos];
        if(!root[pos])
        {
            root[pos] = ++cnt;
            tree[cnt] = k;
            size[cnt] = num[cnt] = 1;
            sum[cnt] = k.v;
            return;
        }
        while(1)
        {
            if(tree[now].a == k.a)
            {
                ++num[now];
                up(now);
                break;
            }
            if(!child[now][k.a > tree[now].a])
            {
                child[now][k.a > tree[now].a] = ++cnt;
                tree[cnt] = k;
                size[cnt] = num[cnt] = 1;
                fa[cnt] = now;
                sum[cnt] = k.v;
                up(cnt);
                splay(cnt, 0, pos);
                break;
            }
            now = child[now][k.a > tree[now].a];
        }
    }
} using namespace splaytree;
namespace segmenttree
{
    void update(int l, int r, int x, int pos, data &k)
    {
        if(l == r)
        {
            root[x] = ++cnt;
            tree[cnt] = k;
            num[cnt] = size[cnt] = 1;
            sum[cnt] = k.v;
            return;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) update(l, mid, x << 1, pos, k);
        else update(mid + 1, r, x << 1 | 1, pos, k);
        int t = find(x, a[pos]);
        del(x, t); insert(x, k);
    }
    void build(int l, int r, int x)
    {
        if(l == r)
        {
            root[x] = ++cnt;
            num[cnt] = size[cnt] = 1;
            tree[cnt] = a[l];
            sum[cnt] = a[l].v;
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1);
        build(mid + 1, r, x << 1 | 1);
        for(int i = l; i <= r; ++i) insert(x, a[i]);
    }
    ll querybig(int l, int r, int x, int a, int b, data &k)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return getbig(x, k) % mod;
        int mid = (l + r) >> 1;
        return ((querybig(l, mid, x << 1, a, b, k) +
                querybig(mid + 1, r, x << 1 | 1, a, b, k)) % mod);
    }
    ll querysmall(int l, int r, int x, int a, int b, data &k)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return getsmall(x, k) % mod;
        int mid = (l + r) >> 1;
        return ((querysmall(l, mid, x << 1, a, b, k) +
                querysmall(mid + 1, r, x << 1 | 1, a, b, k)) % mod);
    }
} using namespace segmenttree;
int main()
{
    n = read(); m = read();
    for(int i = 1; i <= n; ++i)
    {
        a[i].a = read(); a[i].v = read();
        ans = ((ans + B.query(50001, a[i].v) - B.query(a[i].a, a[i].v)) % mod + mod) % mod;
        B.update(a[i].a, a[i].v);
    }
    build(1, n, 1);
    while(m--)
    {
        int x, y; x = read(); y = read();
        if(x > y) swap(x, y);
        if(x == y)
        {
            printf("%lld\n", ans);
            continue;
        }
        if(a[x].a < a[y].a) ans += a[x].v + a[y].v;
        else ans -= a[x].v + a[y].v;
        ll a1 = querybig(1, n, 1, x + 1, y - 1, a[x]);
        ll a2 = querysmall(1, n, 1, x + 1, y - 1, a[x]);
        ll a3 = querysmall(1, n, 1, x + 1, y - 1, a[y]);
        ll a4 = querybig(1, n, 1, x + 1, y - 1, a[y]);
        ans = ((ans + a1 - a2 + a3 - a4) % mod + mod) % mod;
        update(1, n, 1, x, a[y]);
        update(1, n, 1, y, a[x]);
        swap(a[x], a[y]);
        printf("%lld\n", ans);
    }
    return 0;
}

时间: 2024-12-12 04:03:14

bzoj4889的相关文章

【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT

[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000),每次交换两个数的位置,交换m次(m<=50000) 求每次交换后的序列的杂乱度对1e9+7取模(对于每一对是逆序对的编码会产生两者权值和的杂乱度). 感觉正解是什么奇怪的树套树?蒟蒻只会分块水题.. 先用BIT求一遍初始状态的杂乱度..(不要问我为什么一开始是BIT..因为打暴力正好用到就懒得改了.

[bzoj4889] [Tjoi2017]不勤劳的图书管理员

Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置.因为小豆被要求在接下来的m天中至少要整理一次图书.小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理. Input 第一行会有两个数,n,m分别表示有n本书,m天 接下来n行,每行两个数