利用树的dfs序解决问题:
就是dfs的时候记录每个节点的进入时间和离开时间,这样一个完整的区间就是一颗完整的树,就转化成了区间维护的问题。
比如hdu3887 本质上是一个求子树和的问题
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <algorithm> 5 #include <iostream> 6 #include <stack> 7 //#pragma comment(linker,"/STACK:1024000000,1024000000") 8 using namespace std; 9 #define MAXN (200000+10) 10 #define lowbit(i) (i&(-i)) 11 int n,m; 12 struct BIT{ 13 int t[MAXN]; 14 BIT(){memset(t,0,sizeof(t));} 15 void init(){memset(t,0,sizeof(t));} 16 int _query(int a){ 17 int ans=0; 18 for (int i=a;i>=1;i-=lowbit(i)) ans+=t[i]; 19 return ans; 20 } 21 void modify(int a,int x){ 22 for (int i=a;i<=n;i+=lowbit(i)) t[i]+=x; 23 } 24 25 int query(int a,int b){ 26 return _query(b)-_query(a-1); 27 } 28 }T; 29 int timemark; 30 int intime[MAXN],outime[MAXN]; 31 int data[MAXN]; 32 int f[MAXN]; 33 int head[MAXN],next[MAXN],e[MAXN],countside; 34 void buildside(int a,int b){ 35 e[countside]=b; 36 next[countside]=head[a]; 37 head[a]=countside++; 38 } 39 /* 40 void dfs(int x,int fa){ 41 intime[x]=timemark++; 42 for (int i=head[x];i>0;i=next[i]){ 43 if (e[i]!=fa){ 44 dfs(e[i],x); 45 } 46 } 47 outime[x]=timemark++; 48 } 49 */ 50 51 stack<int> s; 52 bool instack[MAXN]; 53 void dfs(int root){ 54 memset(instack,false,sizeof instack); 55 s.push(root); 56 intime[root]=timemark++; 57 instack[root]=true; 58 while (!s.empty()){ 59 bool loop=false; 60 int now=s.top(); 61 for (int i=head[now];i>0;i=next[i]){ 62 if (!instack[e[i]]){ 63 s.push(e[i]); 64 instack[e[i]]=true; 65 intime[e[i]]=timemark++; 66 loop=true; 67 break; 68 } 69 } 70 if (loop) continue; 71 s.pop(); 72 outime[now]=timemark++; 73 } 74 } 75 76 int main (int argc, char *argv[]) 77 { 78 int p; 79 int a,b; 80 char cmd[10]; 81 82 while (1){ 83 scanf("%d%d",&n,&p); 84 85 if (n==0 && p==0) break; 86 87 memset(head,0,sizeof head); 88 memset(next,0,sizeof next); 89 memset(e,0,sizeof e); 90 91 countside=1; 92 for (int i=1;i<=n-1;i++){ 93 scanf("%d%d",&a,&b); 94 buildside(a,b); 95 buildside(b,a); 96 } 97 98 timemark=1; 99 dfs(p); 100 101 102 /*for (int i=1;i<=n;i++) cout<<intime[i]<<" "<<outime[i]<<endl;*/ 103 104 int N=n; 105 n=n*2; 106 T.init(); 107 for (int i=1;i<=n;i++){ 108 data[i]=1; 109 T.modify(i,1); 110 } 111 112 for (int i=N;i>=1;i--){ 113 f[i]=(T.query(intime[i],outime[i])-2)/2; 114 T.modify(intime[i],-1); 115 T.modify(outime[i],-1); 116 } 117 118 for (int i=1;i<=N-1;i++) printf("%d ",f[i]); 119 printf("%d\n",f[N]); 120 } 121 return 0; 122 }
直接dfs爆栈了,所以我写了一个手工栈。结果后来发现这样就行了QAQ
1 #pragma comment(linker,"/STACK:100000000,100000000")
WTF。。。涨姿势了
再就是对于那种复杂的序列操作问题,比如文本编辑器,我发现了C++ 里还有rope这个东西。当然这不是标准STL的,这是SGI STL的一部分。但是如果比赛的时候能用就爽了。。。不管怎么说先记录一下,平时也是蛮实用的。
rope就是一个能支持各种操作的序列,crope就是rope的字符串版本。rope自带各种炫酷的功能,时间各种logn,就连空间也超小。据说内部实现的是一个可持久化的平衡数并且加上共享节点。Orz
NOI 的那道文本编辑器
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <ext/rope> 6 using namespace std; 7 using namespace __gnu_cxx; 8 crope List; 9 int n,now,k; 10 char s[2500005]; 11 int main() 12 { 13 char cmd[25]; 14 int i; 15 for (scanf("%d",&n);n--;) 16 { 17 scanf("%s",cmd); 18 if (cmd[0]=='M') scanf("%d",&now); 19 else if (cmd[0]=='I') 20 { 21 scanf("%d%*c",&k); 22 for (i=0;i<k;i++) do 23 { 24 scanf("%c",&s[i]); 25 }while(s[i]=='\n'); 26 s[k]=0; 27 List.insert(now,s); 28 } 29 else if (cmd[0]=='D') 30 { 31 scanf("%d",&k); 32 List.erase(now,k); 33 } 34 else if (cmd[0]=='G') 35 { 36 scanf("%d",&k); 37 List.copy(now,k,s); 38 s[k]=0; 39 puts(s); 40 } 41 else if (cmd[0]=='P') now--; 42 else now++; 43 } 44 return 0; 45 }