树(Persistent Bookcase,cf 707d)

觉得无非就是存起来或者原路找回去。

存起来需要太多的空间,肯定不行的。

讲道理,原路找回去好难编程实现,一会往前一会往后,而且多走了很多路。

这就是为什么要用某种数据结构建模的原因吧。

真的能显著降低编程难度,而且思路十分清晰。

看到这种回溯的东西,应该要想到树的。。。

用了树之后访问顺序有所变化,但这反而少走了很多路。

建模思想还不够吧。。。


n个点的多叉树,必有n-1条边。

dfs经常会出现访问顺序不如意的情况,那就记录下来,然后再循环一遍输出吧。

老是希望一遍dfs搞定所有问题,有点钻牛角尖了,这样只会使编程复杂度增加很多,思路极不清晰,很容易出错,然而效率却没有显著的提升,不值。比赛中编程复杂度也是很重要的参考。


参考 http://www.cnblogs.com/Coolxxx/p/5792237.html


他没有用线段树。

对比:

查询都是O(1)。

单点更新他是O(1),我是log(n*m)。

区间更新他是O(m),我是log(n*m)。

跑了一下其实差不多快。

线段树的优点是区间更新与查询快,但是单点更新慢。


速度差别不大的主要原因是

1、每次查询都是查全部,因此线段树最大的优势没了。

2、每次区间更新的长度都很短,因此线段树次要的优势被严重压制。

3、单点更新非常多,线段树劣势被放大。
最后就差不多快了。


这道题的核心是建树与dfs吧。


我的代码

#include<stdio.h>
#include<vector>
#define maxn 1000010
using namespace std;

int tree[maxn<<2];
bool add[maxn<<2];

bool D(int l,int r,int now,int a,int b)
{
    if(l==r)
    {
        bool deng=tree[now]==b;
        tree[now]=b;
        return deng;
    }
    int m=(l+r)>>1;
    int ls=now<<1;
    int rs=ls|1;
    if(add[now])
    {
        add[ls]^=1;
        add[rs]^=1;
        add[now]=0;
        tree[ls]=m-l+1-tree[ls];
        tree[rs]=r-m-tree[rs];
        tree[now]=tree[ls]+tree[rs];
    }
    bool deng;
    if(a<=m) deng=D(l,m,ls,a,b);
    else deng=D(m+1,r,rs,a,b);
    tree[now]=tree[ls]+tree[rs];
    return deng;
}

void Q(int l,int r,int now,int ql,int qr)
{
    if(l>qr||r<ql) return;
    if(ql<=l&&qr>=r)
    {
        add[now]^=1;
        tree[now]=r-l+1-tree[now];
        return;
    }
    int m=(l+r)>>1;
    int ls=now<<1;
    int rs=ls|1;
    if(add[now])
    {
        add[ls]^=1;
        add[rs]^=1;
        add[now]=0;
        tree[ls]=m-l+1-tree[ls];
        tree[rs]=r-m-tree[rs];
        tree[now]=tree[ls]+tree[rs];
    }
    Q(l,m,ls,ql,qr);
    Q(m+1,r,rs,ql,qr);
    tree[now]=tree[ls]+tree[rs];
}

void print(int l,int r,int now)
{
    int m=(l+r)>>1;
    int ls=now<<1;
    int rs=ls|1;
    if(add[now])
    {
        add[ls]^=1;
        add[rs]^=1;
        add[now]=0;
        tree[ls]=m-l+1-tree[ls];
        tree[rs]=r-m-tree[rs];
        tree[now]=tree[ls]+tree[rs];
    }
    printf("%d\n",tree[1]);
}

struct op
{
    int id;
    int a,b;
    vector<int>next;
    op(int A,int B,int C):id(A),a(B),b(C){}
};

int n,m,q;
vector<op>vec;

void dfs(op now)
{
    bool deng;
    switch (now.id)
    {
    case 1:
        deng=D(1,n*m,1,(now.a-1)*m+now.b,1);
        break;
    case 2:
        deng=D(1,n*m,1,(now.a-1)*m+now.b,0);
        break;
    case 3:
        Q(1,n*m,1,(now.a-1)*m+1,now.a*m);
    }

    print(1,n*m,1);
    for(unsigned int i=0;i<now.next.size();i++)
        dfs(vec[now.next[i]]);

    switch (now.id)
    {
    case 1:
        if(!deng)
            D(1,n*m,1,(now.a-1)*m+now.b,0);
        break;
    case 2:
        if(!deng)
            D(1,n*m,1,(now.a-1)*m+now.b,1);
        break;
    case 3:
        Q(1,n*m,1,(now.a-1)*m+1,now.a*m);
    }
}

void init()
{
    scanf("%d %d %d",&n,&m,&q);
    int id,a,b;
    vec.push_back(op(0,0,0));
    while(q--)
    {
        scanf("%d",&id);
        switch (id)
        {
        case 1:
        case 2:
            scanf("%d %d",&a,&b);
            vec.push_back(op(id,a,b));
            break;
        case 3:
        case 4:
            scanf("%d",&a);
            vec.push_back(op(id,a,0));
            break;
        }
    }
    for(unsigned int i=1;i<vec.size();i++)
    {
        if(vec[i].id==4)
            vec[vec[i].a].next.push_back(i);
        else
            vec[i-1].next.push_back(i);
    }
    for(unsigned int i=0;i<vec[0].next.size();i++)
        dfs(vec[vec[0].next[i]]);
}

int main()
{
    init();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值