BZOJ 1251 绳命中第一道SPLAY

不要问蒟蒻标题是怎么回事。蒟蒻就是蒟蒻,T^T到现在才会写SPLAY。

感觉这道题的SPLAY也没啥好讲的,很基础。第一次写SPLAY,不过思路还是比较明朗。只不过最开始写这道题的时候傻乎乎的只给“加”的操作打标记,没给“翻转”打标记,T了一次。再加上自己这凌乱的代码、数不清的细节错误,调了老长时间。

有这么一些值得我注意的细节:

  1. find()过程中要pushdown
  2. rotate()前要分别pushdown父节点和当前节点,之后要分别maintain父节点和当前节点
  3. rotate()过程中别忘了P[fa].fa的一个字节点指针要改变
  4. 合并和分裂操作过程中也要pushdown和maintain
  5. 注意P[0]的值不要影响有效的节点的值的计算
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

void get (int &x)
{
    char c = getchar(); bool neg = 0; x = 0;
    while (c < '0' || c > '9') {if (c == '-') neg = 1; c = getchar();}
    while (c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
    if (neg) x = -x;
}
void put (int x)
{
    if (x < 0) {putchar ('-'); x = -x;}
    if (x == 0) {putchar ('0');}
    char s[15]; int num = 0;
    while (x) s[++num] = (x%10)+48, x /= 10;
    while (num) putchar (s[num--]);
    putchar ('\n');
}

struct node 
{
    int k, lc, rc, fa, sz, ad, re, mx;
    void reset() {k=lc=rc=fa=sz=ad=re=0; mx=-(1<<30);}
};

struct SplayTree
{
    node P[50005]; int cnt, root;

    void build (int rt, int sz)
    {
        P[rt].sz = sz; int half = sz>>1;
        if (half) {P[++cnt].fa=rt, P[rt].lc=cnt; build(cnt,half);}
        half = sz - half - 1;
        if (half) {P[++cnt].fa=rt, P[rt].rc=cnt; build(cnt,half);}
    }
    void initialize (int sz) {build(cnt=root=1, sz);}

    void pushdown (int rt)
    {
        if (P[rt].ad)
        {
            int ad = P[rt].ad, lc = P[rt].lc, rc = P[rt].rc;
            P[lc].k += ad, P[lc].ad += ad, P[lc].mx += ad;
            P[rc].k += ad, P[rc].ad += ad, P[rc].mx += ad;
            P[rt].ad = 0;
        }
        if (P[rt].re)
        {
            int lc = P[rt].lc, rc = P[rt].rc;
            swap(P[lc].lc, P[lc].rc);
            swap(P[rc].lc, P[rc].rc);
            P[lc].re ^= 1, P[rc].re ^= 1;
            P[rt].re = 0;
        }
    }

    void maintain (int rt)
    {
        P[0].reset();
        int lc = P[rt].lc, rc = P[rt].rc;
        P[rt].sz = P[lc].sz + P[rc].sz + 1;
        P[rt].mx = max (max(P[lc].mx,P[rc].mx), P[rt].k);
    }

    int find (int rt, int k)
    {
        int rk = P[P[rt].lc].sz+1;
        if (rk == k) return rt;
        pushdown(rt);
        if (rk > k) return find (P[rt].lc, k);
        if (rk < k) return find (P[rt].rc, k-rk);
    }

    void rotate (int rt)
    {
        int fa = P[rt].fa, gfa = P[fa].fa;
        pushdown(fa); pushdown(rt);
        if (P[fa].lc == rt)
        {
            P[fa].lc = P[rt].rc, P[P[rt].rc].fa = fa;
            P[rt].rc = fa, P[fa].fa = rt;
        }
        else
        {
            P[fa].rc = P[rt].lc, P[P[rt].lc].fa = fa;
            P[rt].lc = fa, P[fa].fa = rt;
        }
        if(P[gfa].lc==fa) P[gfa].lc=rt; 
        else P[gfa].rc=rt;
        P[rt].fa = gfa;
        if (fa == root) root = rt, P[rt].fa = 0;
        maintain(fa); maintain(rt);
    }
    void splay (int rt)
    {
        while(rt!=root)
        {
            int fa = P[rt].fa, gfa = P[fa].fa;
            if(gfa&&(P[fa].lc==rt)==(P[gfa].lc==fa)) rotate(fa);
            rotate(rt);
        }
    }

    void merge (int L, int R)
    {
        if (!L) {root=R; return;}
        if (!R) {root=L; return;}
        root = L;
        splay (find(L,P[L].sz));
        pushdown (root);
        P[root].rc = R, P[R].fa = root;
        maintain (root);
    }

    int split (int k, bool po)
    {
        int rt = find (root, k), t;
        splay (rt); pushdown (rt);
        if (po) t=P[rt].lc, P[rt].lc=0;
        else t=P[rt].rc, P[rt].rc=0;
        P[t].fa = 0; maintain(rt);
        return t;
    }

    void add (int L, int R, int V)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        P[root].k+=V, P[root].mx+=V, P[root].ad+=V;
        merge (root,op2);
        merge (op, root);
    }

    void rever (int L, int R)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        swap(P[root].lc, P[root].rc);
        P[root].re ^= 1;
        merge (root,op2);
        merge (op, root);
    }

    void getmax (int L, int R)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        put (P[root].mx);
        merge (root,op2);
        merge (op, root);
    }
}Solve;

int n, m;

int main ()
{
    get (n); get (m);
    Solve.initialize(n);
    while (m--)
    {
        int cmd, L, R, V; get (cmd); get (L); get (R);
        if (cmd == 1) {get (V); Solve.add(L,R,V);}
        if (cmd == 2) Solve.rever(L,R); 
        if (cmd == 3) Solve.getmax(L,R);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值