树(Persistent Bookcase,cf 707d)
来源:互联网 发布:mac os 10.12 原版 编辑:程序博客网 时间:2024/06/05 18:24
觉得无非就是存起来或者原路找回去。
存起来需要太多的空间,肯定不行的。
讲道理,原路找回去好难编程实现,一会往前一会往后,而且多走了很多路。
这就是为什么要用某种数据结构建模的原因吧。
真的能显著降低编程难度,而且思路十分清晰。
看到这种回溯的东西,应该要想到树的。。。
用了树之后访问顺序有所变化,但这反而少走了很多路。
建模思想还不够吧。。。
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 1000010using 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
- 树(Persistent Bookcase,cf 707d)
- CF #368 D Persistent Bookcase 操作树~?
- Codeforces 707D Persistent Bookcase(DFS)
- codeforces 707D Persistent Bookcase
- CodeForces 707D - Persistent Bookcase
- codeforces--707D. Persistent Bookcase
- 【离线】【深搜】【树】Codeforces 707D Persistent Bookcase
- [可持久化线段树] codeforces 707D. Persistent Bookcase
- Codeforces 707D Persistent Bookcase(bitset+dfs)★
- codeforces 707 D Persistent Bookcase(dfs+bitset)
- CodeForces 707D Persistent Bookcase (操作建树DFS|主席树+主席树)
- Codeforces 707D.Persistent Bookcase(离线算法,dfs树,好题!)
- 【21.28%】【codeforces 707D】Persistent Bookcase
- codeforces 707D Persistent Bookcase 离线+深搜
- Codeforces 707D Persistent Bookcase 暴力(bitset)
- CF368 D - Persistent Bookcase
- Codeforces 707D Persistent Bookcase(离线dfs或在线主席树)
- Codeforces Problem 707D Persistent Bookcase(dfs+bitset)
- javascript的一些基础知识
- 简单的mvp+retrofit+rxjava示例
- 适配器模式
- http://blog.csdn.net/evankaka/article/details/48785513
- python将文件读取为字符串
- 树(Persistent Bookcase,cf 707d)
- 使用NPM + Webpack进行前端开发的示例
- SpringMVC中利用字符集过滤器characterEncodingFilter解决中文乱码
- 用java写的一个排序算法
- CountDownLatch应用
- C++ Socket编程步骤
- Codeforces Round #368 (Div. 2) D. Persistent Bookcase(n层m个的书架的四种操作)
- 设计模式C++版:第五式装饰者模式
- Oracle报错宗介