codeforces 343D Water Tree 树链剖分 dfs序 线段树 set
Posted unnamed05
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces 343D Water Tree 树链剖分 dfs序 线段树 set相关的知识,希望对你有一定的参考价值。
这道题主要是要考虑到同一棵子树中dfs序是连续的
然后我就直接上树剖了。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]; 15 int cnt=1; 16 int top[MAXN],newarr[MAXN],newid[MAXN],siz[MAXN],hardchi[MAXN],par[MAXN]; 17 inline void dfs(const int &v,const int &pa) 18 { 19 siz[v]=1;par[v]=pa; 20 int masiz=0; 21 for(int i=0;i<nei[v].size();i++) 22 { 23 int u=nei[v][i]; 24 if(u==pa) continue; 25 dfs(u,v); 26 siz[v]+=siz[u]; 27 if(siz[u]>masiz) 28 { 29 masiz=siz[u]; 30 hardchi[v]=u; 31 } 32 } 33 } 34 inline void findHardPath(const int &v,const int &Top) 35 { 36 top[v]=Top; 37 newarr[cnt]=v; 38 newid[v]=cnt++; 39 if(hardchi[v]!=-1)findHardPath(hardchi[v],Top); 40 for(int i=0;i<nei[v].size();i++) 41 { 42 int u=nei[v][i]; 43 if(u==par[v]||u==hardchi[v])continue; findHardPath(u,u); 44 } 45 } 46 void built(const int &i,const int &l,const int &r) 47 { 48 tree[i].l=l;tree[i].r=r; 49 if(l==r) return; 50 else 51 { 52 int mid=(l+r)>>1; 53 built(i<<1,l,mid); 54 built(i<<1|1,mid+1,r); 55 } 56 } 57 inline void pushdown(int i) 58 { 59 if(tree[i].value==-1) return; 60 tree[i<<1].value=tree[i].value; 61 tree[i<<1|1].value=tree[i].value; 62 } 63 void change(const int &i,const int &l,const int &r,const int &w) 64 { 65 if(tree[i].l>=l&&tree[i].r<=r) 66 { 67 tree[i].value=w; 68 pushdown(i); 69 return; 70 } 71 else 72 { 73 pushdown(i); 74 int mid=(tree[i].l+tree[i].r)>>1; 75 if(l<=mid)change(i<<1,l,r,w); 76 if(r>mid)change(i<<1|1,l,r,w); 77 if(tree[i<<1].value==tree[i<<1|1].value) tree[i].value=tree[i<<1].value; 78 else tree[i].value=-1; 79 } 80 } 81 int res=-1; 82 inline void query(const int &i,const int &x) 83 { 84 if(tree[i].value!=-1) 85 { 86 res=tree[i].value; 87 return; 88 } 89 int mid=(tree[i].l+tree[i].r)>>1; 90 if(x<=mid)query(i<<1,x); 91 else query(i<<1|1,x); 92 } 93 int main() 94 { 95 int n; 96 scanf("%d",&n); 97 for(int i=0;i<n-1;i++) 98 { 99 int x,y; 100 scanf("%d %d",&x,&y); 101 nei[x].push_back(y); 102 nei[y].push_back(x); 103 } 104 memset(hardchi,-1,sizeof hardchi); 105 dfs(1,1); 106 findHardPath(1,1); 107 built(1,1,n); 108 int m; 109 scanf("%d",&m); 110 for(int i=0;i<m;i++) 111 { 112 int x,y; 113 scanf("%d %d",&x,&y); 114 if(x==1) change(1,newid[y],newid[y]+siz[y]-1,1); 115 else if(x==2) 116 { 117 while(top[y]!=1) 118 { 119 change(1,newid[top[y]],newid[y],0); 120 y=par[top[y]]; 121 } 122 change(1,newid[1],newid[y],0); 123 } 124 else 125 { 126 query(1,newid[y]); 127 printf("%d ",res); 128 } 129 } 130 return 0; 131 }
其实完全不用树链剖分,我们可以重新考虑一下题目中的3种操作
1、将子树全部赋成1,直接dfs序+线段树区间修改
2、将节点的祖先全部赋成0。我们可以知道,如果一个节点的子树中有1个0,那么这个节点一定会被赋成0,所以只要线段树单点修改就可以了。
3、查询。查一下是该节点的子树有没有0,该节点有没有被赋成1,如果都有就再比较一下操作的先后
1 #include <stdio.h> 2 #include <vector> 3 #include <memory.h> 4 #include <algorithm> 5 using namespace std; 6 #define MN 3000005 7 const int oo = 1000000007; 8 int n, m; 9 int top, L[MN], R[MN], l[MN], h[MN], r[MN], d[MN], leaf[MN]; 10 bool pos[MN]; 11 vector <int> G[MN]; 12 void Make(int r, int lo, int hi) { 13 l[r] = lo; h[r] = hi; 14 if (lo == hi) { leaf[lo] = r; return; } 15 Make(r<<1, lo, (lo+hi)>>1); 16 Make((r<<1)+1, (lo+hi)/2+1, hi); 17 } 18 void go(int u) { 19 top++; L[u]= top; pos[u] = 0; 20 int sz = G[u].size(); 21 for (int i = 0; i < sz; i++) if (pos[G[u][i]]) go(G[u][i]); 22 R[u] = top; 23 } 24 void upd(int p, int lo, int hi, int y) { 25 if (l[p] > hi || h[p] < lo) return; 26 if (l[p] >= lo && h[p] <= hi) { r[p] = y; return; } 27 upd(p<<1, lo, hi, y); 28 upd((p<<1)+1, lo, hi, y); 29 } 30 void del(int v, int w) { 31 int p = leaf[v]; 32 while (p) { d[p] = w; p >>= 1; } 33 } 34 int F(int u) { 35 int p = leaf[u], ret = 0; 36 while (p) { if (ret < r[p]) ret = r[p]; p >>= 1; } 37 return ret; 38 } 39 inline int fmax(int a, int b) { if (a > b) return a; return b; } 40 int T(int r, int lo, int hi) { 41 if (l[r] > hi || h[r] < lo) return 0; 42 if (l[r] >= lo && h[r] <= hi) return d[r]; 43 return fmax(T(r<<1,lo,hi), T((r<<1)+1,lo,hi)); 44 } 45 int main() { 46 int u, v, K, s, f; 47 scanf("%d",&n); 48 for (int i = 1; i <= n-1; i++) { 49 scanf("%d%d",&u,&v); 50 G[u].push_back(v); 51 G[v].push_back(u); 52 } 53 memset(pos, 1, sizeof(pos)); 54 go(1); 55 Make(1, 1, n+10); 56 scanf("%d",&m); 57 for (int i = 1; i <= m; i++) { 58 scanf("%d%d",&K,&v); 59 s = L[v]; f = R[v]; 60 if (K == 1) upd(1, s, f, i); 61 if (K == 2) del(s, i); 62 if (K == 3) { 63 if (F(s) > T(1, s, f)) printf("1 "); 64 else printf("0 "); 65 } 66 } 67 return 0; 68 }
其实还可以更简单!
连线段树都不用,直接用set就好了!!
1 #include <bits/stdc++.h> 2 #define N 500005 3 using namespace std; 4 int tid; 5 vector<int> a[N]; 6 int st[N * 2], ed[N * 2], parent[N * 2]; 7 void dfs(int x, int p = 0){ 8 st[x] = ++tid; 9 parent[x] = p; 10 for (int i = 0; i < a[x].size(); ++ i){ 11 int y = a[x][i]; 12 if (y == p) continue; 13 dfs(y, x); 14 } 15 ed[x] = tid; 16 } 17 int main() { 18 int n, q, x, y, c, v; 19 scanf("%d", &n); 20 for (int i = 0; i < n-1; i++) { 21 scanf("%d%d", &x, &y); 22 a[x].push_back(y); 23 a[y].push_back(x); 24 } 25 dfs(1); 26 scanf("%d", &q); 27 set<int> Empty; 28 for (int i = 1; i <= n; i++) Empty.insert(st[i]); 29 Empty.insert(tid+1); 30 for (int i = 1; i <= q; i++) { 31 scanf("%d%d", &c, &v); 32 if (c == 1) { 33 if (*(Empty.lower_bound(st[v])) <= ed[v]) { // it is empty right now 34 if (v > 1) Empty.insert(st[parent[v]]); 35 Empty.erase(Empty.lower_bound(st[v]), Empty.upper_bound(ed[v])); 36 } 37 } 38 if (c == 2) Empty.insert(st[v]); 39 if (c == 3) puts(*(Empty.lower_bound(st[v])) <= ed[v] ? "0" : "1"); 40 } 41 return 0; 42 }
以上是关于codeforces 343D Water Tree 树链剖分 dfs序 线段树 set的主要内容,如果未能解决你的问题,请参考以下文章
codeforces 343D Water Tree 树链剖分 dfs序 线段树 set