hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the highest loyalty for company.Sean want to know who will replace the fired man.

Input

In the first line a number T indicate the number of test cases. Then for each case the first line contain 2 numbers n,m (2<=n,m<=50000),indicate the company has n person include Sean ,m is the times of Sean’s query.Staffs are numbered from 1 to n-1,Sean’s number is 0.Follow n-1 lines,the i-th(1<=i<=n-1) line contains 3 integers a,b,c(0<=a<=n-1,0<=b,c<=1000000),indicate the i-th staff’s superior Serial number,i-th staff’s loyalty and ability.Every staff ‘s Serial number is bigger than his superior,Each staff has different loyalty.then follows m lines of queries.Each line only a number indicate the Serial number of whom should be fired.

Output

For every query print a number:the Serial number of whom would replace the losing job man,If there has no one to replace him,print -1.

Sample Input

1
3 2
0 100 99
1 101 100
1
2

Sample Output

2
-1


  题目大意 给定一棵树,每个点有两个权值,忠诚度和能力值,每次询问点x的子树中能力值大于它,忠诚度最高的一位的编号。

Solution 1 树分块

  因为查询的时候,查询一个节点的子树实际上是等于查询一段区间内的数据,所以考虑对dfs序进行分块。

  按照dfs序进行分块,块内按忠诚度进行排序,再记录后缀忠诚度最大值。

  根据常用套路,每次查询,对于块两端部分,暴力for。中间每个块lower_bound upper_bound一下查询合法的一段,然后用后缀忠诚度最大值进行更新答案就好了。

  (这是我比较笨的分块方法)

  设块的大小为s,块的数量为c,则总时间复杂度为

Code

  1 /**
  2  * hdu
  3  * Problem#4366
  4  * Accepted
  5  * Time: 748ms
  6  * Memory: 8468k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11
 12 typedef class Staff {
 13     public:
 14         int loy;
 15         int abi;
 16         int id;
 17
 18         boolean operator < (Staff b) const {
 19             if(abi != b.abi)    return abi < b.abi;
 20             return loy < b.loy;
 21         }
 22 }Staff;
 23
 24 boolean operator < (const int& x, const Staff& s) {
 25     return x < s.abi;
 26 }
 27
 28 const int maxcsize = 300;
 29 typedef class Chunk {
 30     public:
 31         int len;
 32         Staff sta[maxcsize];
 33         int maxv[maxcsize];
 34         int ans[maxcsize];
 35
 36         void init(Staff* lis, int from, int end) {
 37             len = end - from;
 38             for(int i = from; i < end; i++)
 39                 sta[i - from] = lis[i];
 40             sort(sta, sta + len);
 41             maxv[len] = -1;
 42             ans[len] = -1;
 43             for(int i = len - 1; i >= 0; i--) {
 44                 if(sta[i].loy > maxv[i + 1])
 45                     maxv[i] = sta[i].loy, ans[i] = sta[i].id;
 46                 else
 47                     maxv[i] = maxv[i + 1], ans[i] = ans[i + 1];
 48             }
 49         }
 50
 51         void getAns(int limit, int& rmaxv, int& rans) {
 52             int pos = upper_bound(sta, sta + len, limit) - sta;
 53             if(maxv[pos] > rmaxv)
 54                 rmaxv = maxv[pos], rans = ans[pos];
 55         }
 56 }Chunk;
 57
 58 int n, m;
 59 int cs, cc;
 60 vector<int> *g;
 61 Staff lis[50005];
 62 Staff *nlis;
 63 Chunk chs[300];
 64
 65 inline void init() {
 66     scanf("%d%d", &n, &m);
 67     g = new vector<int>[(n + 1)];
 68     nlis = new Staff[(n + 1)];
 69     for(int i = 1, x; i < n; i++) {
 70         scanf("%d%d%d", &x, &lis[i].loy, &lis[i].abi);
 71         lis[i].id = i;
 72         g[x].push_back(i);
 73     }
 74     lis[0].loy = lis[0].abi = 23333333;
 75     lis[0].id = 0;
 76     cs = sqrt(n + 0.5);
 77 }
 78
 79 int cnt;
 80 int visitID[50005], exitID[50005];
 81 int visit[50005];
 82 inline void dfs(int node) {
 83     visitID[node] = ++cnt;
 84     visit[cnt] = node;
 85     for(int i = 0; i < (signed)g[node].size(); i++)
 86         dfs(g[node][i]);
 87     exitID[node] = cnt;
 88 }
 89
 90 inline void init_chunks() {
 91     for(int i = 1; i <= n; i++)
 92         nlis[i] = lis[visit[i]], nlis[i].id = i;
 93     for(cc = 0; cc * cs < n; cc++)
 94         chs[cc + 1].init(nlis, cc * cs + 1, min((cc + 1) * cs, n) + 1);
 95 }
 96
 97 inline void solve() {
 98     int l, r, x, maxv, ans, lim;
 99     while(m--) {
100         scanf("%d", &x);
101         maxv = -1, ans = -1;
102         l = visitID[x], r = exitID[x], lim = lis[x].abi;
103         int lid = l / cs + 1, rid = r / cs + 1;
104         if(lid == rid) {
105             for(int i = l; i <= r; i++)
106                 if(nlis[i].abi > lim && nlis[i].loy > maxv)
107                     maxv = nlis[i].loy, ans = i;
108         } else {
109 //            if(x == 992)
110 //                putchar(‘a‘);
111             for(int i = l; i <= lid * cs; i++)
112                 if(nlis[i].abi > lim && nlis[i].loy > maxv)
113                     maxv = nlis[i].loy, ans = i;
114             for(int i = (rid - 1) * cs + 1; i <= r; i++)
115                 if(nlis[i].abi > lim && nlis[i].loy > maxv)
116                     maxv = nlis[i].loy, ans = i;
117             for(int i = lid + 1; i < rid; i++)
118                 chs[i].getAns(lim, maxv, ans);
119         }
120         printf("%d\n", (ans == -1) ? (-1) : (visit[ans]));
121     }
122 }
123
124 inline void clear() {
125     delete[] g;
126     delete[] nlis;
127 }
128
129 int T;
130 int main() {
131 //    freopen("a.in", "r", stdin);
132 //    freopen("a.out", "w", stdout);
133     scanf("%d", &T);
134     while(T--) {
135         init();
136         cnt = 0;
137         dfs(0);
138         init_chunks();
139         solve();
140         clear();
141     }
142 //    fprintf(stderr, "Time: %dms\n", clock());
143     return 0;
144 }

Successor(Tree Division)

Solution 2 CDQ分治

  每次查询相当于查询满足能力大于某个值,深度优先时间戳在某一段区间内的最大的忠诚度,感觉有那么一点像偏序的问题,所以上CDQ分治乱搞..

  分治能力,然后对于能力大于等于mid的节点可能会对能力小于mid的节点做出贡献,所以就用一个线段树维护区间最值,对于能力值大于等于mid的节点就在线段树内将它的深度优先时间戳那一位改为它的忠诚度。对于能力值小于mid的节点x就查询[visitID[x], exitID[x]]的最值就好了。

  每次询问O(1)解决。

  总时间复杂度.

  由于自己巨懒无比,CDQ分治从来都不手写队列,直接用vector。又因为线段树和STL中的vector常数巨大无比(当然还有我的代码自带某个比较大的常熟),所以直接上就TLE了。把vector全都改成手写vector才过的。

Code

  1 /**
  2  * hdu
  3  * Problem#4366
  4  * Accepted
  5  * Time: 842ms
  6  * Memory: 18776k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 const signed int inf = (signed)((1u << 31) - 1);
 11
 12 typedef class SegTreeNode {
 13     public:
 14         int val;
 15         int maxid;
 16         SegTreeNode *l, *r;
 17         SegTreeNode():val(-1), maxid(0), l(NULL), r(NULL) {        }
 18
 19         inline void pushUp() {
 20             if(l->val > r->val)
 21                 val = l->val, maxid = l->maxid;
 22             else
 23                 val = r->val, maxid = r->maxid;
 24         }
 25 }SegTreeNode;
 26
 27 SegTreeNode pool[200000];
 28 SegTreeNode *top;
 29
 30 inline SegTreeNode* newnode() {
 31     top->val = -1;
 32     return top++;
 33 }
 34
 35 typedef class SegTree {
 36     public:
 37         SegTreeNode* root;
 38
 39         SegTree():root(NULL) {        }
 40         SegTree(int n) {
 41             build(root, 1, n);
 42         }
 43
 44         void build(SegTreeNode*& node, int l, int r) {
 45             node = newnode();
 46             if(l == r)    return;
 47             int mid = (l + r) >> 1;
 48             build(node->l, l, mid);
 49             build(node->r, mid + 1, r);
 50         }
 51
 52         void update(SegTreeNode*& node, int l, int r, int idx, int val) {
 53             if(l == r) {
 54                 node->val = val, node->maxid = l;
 55                 return;
 56             }
 57             int mid = (l + r) >> 1;
 58             if(idx <= mid)    update(node->l, l, mid, idx, val);
 59             else update(node->r, mid + 1, r, idx, val);
 60             node->pushUp();
 61         }
 62
 63         int query(SegTreeNode*& node, int l, int r, int ql, int qr, int& maxid) {
 64             if(l == ql && qr == r) {
 65                 maxid = node->maxid;
 66                 return node->val;
 67             }
 68             int mid = (l + r) >> 1;
 69             if(qr <= mid)    return query(node->l, l, mid, ql, qr, maxid);
 70             if(ql > mid)    return query(node->r, mid + 1, r, ql, qr, maxid);
 71             int a, b, c;
 72             a = query(node->l, l, mid, ql, mid, c);
 73             b = query(node->r, mid + 1, r, mid + 1, qr, maxid);
 74             if(a > b)    maxid = c;
 75             return max(a, b);
 76         }
 77 }SegTree;
 78
 79 template<typename T>
 80 class Vector {
 81     protected:
 82         int cap;
 83         int siz;
 84         T* l;
 85     public:
 86         Vector():l(NULL), cap(0), siz(0) {    }
 87
 88         inline void push_back(T x) {
 89             if(l == NULL) {
 90                 l = new T[4];
 91                 cap = 4, siz = 0;
 92             }
 93             if(siz == cap) {
 94                 l = (T*)realloc(l, sizeof(T) * cap * 2);    //重新申请内存,并拷贝数组
 95                 cap = cap << 1;
 96             }
 97             l[siz++] = x;
 98         }
 99
100         T& operator [] (int pos) {
101             return l[pos];
102         }
103
104         inline int size() {
105             return siz;
106         }
107
108         inline int capt() {
109             return cap;
110         }
111
112         inline void clear() {
113             delete[] l;
114             l = NULL;
115         }
116 };
117
118 int n, m;
119 int valmax;
120 Vector<int> *g;
121 Vector<int> a233;
122 int* loys, *abis;
123 SegTree st;
124
125 inline void init() {
126     scanf("%d%d", &n, &m);
127     top = pool;
128     g = new Vector<int>[(n + 1)];
129     loys = new int[(n + 1)];
130     abis = new int[(n + 1)];
131     st = SegTree(n);
132     loys[0] = inf, abis[0] = inf;
133     a233.clear();
134     for(int i = 1, x; i < n; i++) {
135         scanf("%d%d%d", &x, loys + i, abis + i);
136         g[x].push_back(i);
137         a233.push_back(i);
138     }
139 }
140
141 int buf[50005];
142 void discrete() {
143     memcpy(buf, abis, sizeof(int) * n);
144     sort(buf, buf + n);
145     valmax = unique(buf, buf + n) - buf;
146     for(int i = 0; i < n; i++)
147         abis[i] = lower_bound(buf, buf + valmax, abis[i]) - buf + 1;
148 }
149
150 int cnt;
151 int visitID[50005], exitID[50005];
152 int visit[50005];
153 inline void dfs(int node) {
154     visitID[node] = ++cnt;
155     visit[cnt] = node;
156     for(int i = 0; i < (signed)g[node].size(); i++)
157         dfs(g[node][i]);
158     exitID[node] = cnt;
159 }
160
161 int maxvals[50005];
162 int ans[50005];
163 void CDQDividing(int l, int r, Vector<int>& q) {
164     if(q.size() <= 1)    return;
165     if(l == r) return;
166
167     int mid = (l + r) >> 1, a, b;
168
169     Vector<int> ql, qr;
170     for(int i = 0; i < (signed)q.size(); i++)
171         if(abis[q[i]] > mid)
172             qr.push_back(q[i]), st.update(st.root, 1, n, visitID[q[i]], loys[q[i]]);
173         else
174             ql.push_back(q[i]);
175
176     for(int i = 0; i < (signed)ql.size(); i++) {
177         a = st.query(st.root, 1, n, visitID[ql[i]], exitID[ql[i]], b);
178         if(a > maxvals[ql[i]])
179             maxvals[ql[i]] = a, ans[ql[i]] = b;
180     }
181
182     for(int i = 0; i < (signed)qr.size(); i++)
183         st.update(st.root, 1, n, visitID[qr[i]], -1);
184
185     q.clear();
186     CDQDividing(l, mid, ql);
187     CDQDividing(mid + 1, r, qr);
188 }
189
190 inline void solve() {
191     cnt = 0;
192     dfs(0);
193     memset(maxvals, -1, sizeof(int) * (n + 1));
194     memset(ans, -1, sizeof(int) * (n + 1));
195     CDQDividing(1, valmax, a233);
196     int x;
197     while(m--) {
198         scanf("%d", &x);
199         printf("%d\n", (ans[x] == -1) ? (-1) : (visit[ans[x]]));
200     }
201 }
202
203 inline void clear() {
204     delete[] g;
205     delete[] loys;
206     delete[] abis;
207 }
208
209 int T;
210 int main() {
211     scanf("%d", &T);
212     while(T--) {
213         init();
214         discrete();
215         solve();
216         clear();
217     }
218     return 0;
219 }

Successor(CDQ Divide and Conquer)

Sulution 3 线段树合并

  对于上一种做法,为了满足子树的关系多带了个log,考虑直接dfs,每一个点先访问它的子树,再把子树信息合并起来,就可以满足子树关系了。

  现在考虑如何维护子树信息。对能力值开一个值域线段树,记录当前值域内最大的忠诚度。

  于是就成功把总时间复杂度优化成.

  然而常熟更大了,所以没有快多少。

Code

  1 /**
  2  * hdu
  3  * Problem#4366
  4  * Accepted
  5  * Time: 436ms
  6  * Memory: 39124k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 const signed int inf = (signed)((1u << 31) - 1);
 11
 12 typedef class SegTreeNode {
 13     public:
 14         int val;
 15         int maxid;
 16         SegTreeNode *l, *r;
 17         SegTreeNode():val(-1), maxid(-1), l(NULL), r(NULL) {        }
 18         SegTreeNode(SegTreeNode *p):val(-1), maxid(-1), l(p), r(p) {        }
 19
 20         inline void pushUp() {
 21             if(l->val > r->val)
 22                 val = l->val, maxid = l->maxid;
 23             else
 24                 val = r->val, maxid = r->maxid;
 25         }
 26 }SegTreeNode;
 27
 28 SegTreeNode pool[1000000];
 29 SegTreeNode null = SegTreeNode(&null);
 30 SegTreeNode *top;
 31
 32 inline SegTreeNode* newnode() {
 33     top->val = -1;
 34     top->maxid = -1;
 35     top->l = top->r = &null;
 36     return top++;
 37 }
 38
 39 void merge(SegTreeNode*& a, SegTreeNode* b) {
 40     if(b == &null)    return;
 41     if(a == &null) {
 42         a = b;
 43         return;
 44     }
 45     if(b->val > a->val)
 46         a->val = b->val, a->maxid = b->maxid;
 47     merge(a->l, b->l);
 48     merge(a->r, b->r);
 49 //    a->pushUp();
 50 }
 51
 52 typedef class SegTree {
 53     public:
 54         SegTreeNode* root;
 55
 56         SegTree():root(&null) {        }
 57
 58         void update(SegTreeNode*& node, int l, int r, int idx, int val, int id) {
 59             if(node == &null)
 60                 node = newnode();
 61             if(l == r) {
 62                 if(val > node->val)
 63                     node->val = val, node->maxid = id;
 64                 return;
 65             }
 66             int mid = (l + r) >> 1;
 67             if(idx <= mid)    update(node->l, l, mid, idx, val, id);
 68             else update(node->r, mid + 1, r, idx, val, id);
 69             node->pushUp();
 70         }
 71
 72         int query(SegTreeNode*& node, int l, int r, int ql, int qr, int& maxid) {
 73             if(l == ql && qr == r) {
 74                 maxid = node->maxid;
 75                 return node->val;
 76             }
 77             int mid = (l + r) >> 1;
 78             if(qr <= mid)    return query(node->l, l, mid, ql, qr, maxid);
 79             if(ql > mid)    return query(node->r, mid + 1, r, ql, qr, maxid);
 80             int a, b, c;
 81             a = query(node->l, l, mid, ql, mid, c);
 82             b = query(node->r, mid + 1, r, mid + 1, qr, maxid);
 83             if(a > b)    maxid = c;
 84             return max(a, b);
 85         }
 86 }SegTree;
 87
 88 const int limval = 1000000;
 89
 90 int n, m;
 91 int valmax;
 92 vector<int> *g;
 93 int* loys, *abis;
 94
 95 inline void init() {
 96     scanf("%d%d", &n, &m);
 97     top = pool;
 98     g = new vector<int>[(n + 1)];
 99     loys = new int[(n + 1)];
100     abis = new int[(n + 1)];
101     loys[0] = inf, abis[0] = inf;
102     for(int i = 1, x; i < n; i++) {
103         scanf("%d%d%d", &x, loys + i, abis + i);
104         g[x].push_back(i);
105     }
106 }
107
108 int buf[50005];
109 void discrete() {
110     memcpy(buf, abis, sizeof(int) * n);
111     sort(buf, buf + n);
112     valmax = unique(buf, buf + n) - buf;
113     for(int i = 0; i < n; i++)
114         abis[i] = lower_bound(buf, buf + valmax, abis[i]) - buf + 1;
115 }
116
117 int ans[50005];
118 int maxv[50005];
119 SegTreeNode* dfs(int node) {
120     SegTree st;
121 //    if(node == 10)
122 //        fprintf(stderr, "gg");
123     for(int i = 0; i < (signed)g[node].size(); i++) {
124         SegTreeNode* buf = dfs(g[node][i]);
125         merge(st.root, buf);
126     }
127     if(node) {
128         maxv[node] = st.query(st.root, 1, n, abis[node] + 1, n, ans[node]);
129         st.update(st.root, 1, n, abis[node], loys[node], node);
130     } else ans[node] = -1;
131     return st.root;
132 }
133
134 inline void solve() {
135     dfs(0);
136     int x;
137     while(m--) {
138         scanf("%d", &x);
139         printf("%d\n", (ans[x]));
140     }
141 }
142
143 inline void clear() {
144     delete[] g;
145     delete[] loys;
146     delete[] abis;
147 }
148
149 int T;
150 int main() {
151 //    freopen("a.in", "r", stdin);
152 //    freopen("a.out", "w", stdout);
153     scanf("%d", &T);
154     while(T--) {
155         init();
156         discrete();
157         solve();
158         clear();
159     }
160     return 0;
161 }
时间: 2024-10-25 03:25:43

hdu 4366 Successor - CDQ分治 - 线段树 - 树分块的相关文章

HDU 4366 Successor( DFS序+ 线段树 )

Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2631    Accepted Submission(s): 634 Problem Description Sean owns a company and he is the BOSS.The other Staff has one Superior.every st

HDU 6183 Color it cdq分治 + 线段树 + 状态压缩

Color it Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Problem Description Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from

HDU 4366 Successor(线段树 DFS时间戳啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4366 Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2961    Accepted Submission(s): 689 Problem Description Sean owns a company and he

ACdream1157 Segments(CDQ分治 + 线段树)

题目这么说的: 进行如下3种类型操作:1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]2)C i (1-base) 删除第i条增加的线段,保证每条插入线段最多插入一次,且这次删除操作一定合法3) Q L R(1 <= L <= R <= 1000000000) 查询目前存在的线段中有多少条线段完全包含[L,R]这个线段,线段X被线段Y完全包含即LY <= LX <= RX <= RY) 初学CDQ分治是看了B

HDU 5126 stars cdq分治+树状数组

题目链接:点击打开链接 题意: T个case n个操作 1. (x,y,z) 在三维平面的点上增加1 2.询问区间范围内的权值和. 思路: cdq分治套cdq分治,然后套树状数组即可.. #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #inclu

Codechef SEP14 QRECT cdq分治+线段树

题意 支持删除矩阵.插入矩阵.查询当前矩阵与之前有多少个矩阵相交 算相交的时候容斥一下:相交矩形数 = 总矩形数-X轴投影不相交的矩形数-Y轴投影不相交的矩形数-XY轴投影下都不相交的矩形数 最后一项cdq分治解决 不是我的程序--->http://wyfcyx.is-programmer.com/posts/190325.html

BZOJ 2244 SDOI2011 拦截导弹 CDQ分治/二维树状数组

题目大意:给定一个序列,每个元素是一个二元组,等概率选择一LIS,求LIS长度以及每个元素被选中的概率 第一问CDQ分治裸上 第二问用每个元素所在的LIS个数/总LIS个数就是答案 每个元素所在的LIS自己必选,然后统计前面的方案数和后面的方案数 以前面的方案数为例,令f[x]为以x结尾的LIS长度,那么有DP方程: g[i]=Σg[j] (f[j]+1=f[i],j<i,a[j].x<a[i].x,a[j].y<a[i].y) 将所有元素按f值排序,分层DP,每层DP是一个三维偏序,上

BZOJ3262/洛谷P3810 陌上花开 CDQ分治 三维偏序 树状数组

原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 落谷P3810 题意 有$n$个元素,第$i$个元素有$a_i$.$b_i$.$c_i$三个属性,设$f(i)$表示满足$a_j\leq a_i$且$b_j\leq b_i$且$c_j\leq c_i$的$j$的数量.对于$d\in [0,n)$,求$f(i)=d$的数量. $n\leq 100000,max\{a_i,b_i,c_i|i

Boring Class HDU - 5324 (CDQ分治)

Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys? Here is the problem: Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn. Y