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\n",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\n");
64             else printf("0\n");
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 }

 

转载于:https://www.cnblogs.com/unnamed05/p/9304276.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值