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;
}
View Code

 

posted @ 2017-06-01 22:25  19992147  阅读(219)  评论(0编辑  收藏  举报