Successor HDU - 4366 分块

代码+注释:

  1 /*
  2 题意:
  3 一共有n个人,其中0号是总裁(金字塔顶尖)。后面输入其他n-1个人的信息啊a、b、c,分别代表第i个人的上级是a,他的
  4 忠诚度为b,他的能力为c。后面有m次询问。他问你能不能找到一个能力比他高的,且忠诚度最高的人。(注意能力只需要
  5 大于此人就可以,不需要最高)
  6
  7
  8 题解:
  9 这道题目用的是分块的方法
 10
 11 首先需要跑一遍dfs来确定每一个人所处于金字塔的位置。从总裁开始向他的下属跑dfs(注意是dfs不是bfs)
 12 因为这样我们最后会得到一个pre数组和一个last数组。这两个数组的作用就是来看某个人x他在金字塔中的位置
 13 以及他的下属最大的位置(这个位置的值是cnt)。那么pre[x]到last[x]之间的所有人都是x的下属
 14
 15 然后分块也是按照位置的编号进行分块的,这个样子维护也好维护。分块后会得到一个maxx数组,这个数组的作用就是
 16 maxx[x][y]:在第x个块里,能力大于y且忠诚度最高的值,这个p[x][y]存放的是这个值所对应的人
 17
 18 id数组里面放的是就是,id[x]表示:位置为x的人的在输入中的编号是多少
 19
 20 具体看代码
 21 */
 22 #include<stdio.h>
 23 #include<string.h>
 24 #include<iostream>
 25 #include<algorithm>
 26 #include<math.h>
 27 #include<vector>
 28 using namespace std;
 29 const int maxn=50005;
 30 const int maxm=sqrt(50000)+5;
 31 int n,m,block,num;
 32 int belong[maxn],l[maxn],r[maxn],last[maxn],cnt=0,pre[maxn];
 33 int id[maxn],v[maxn],a[maxn],maxx[maxm][maxm],p[maxm][maxm];
 34 struct node
 35 {
 36     int ability,loyalty,id;
 37     node(int l=0,int a=0,int id=0):loyalty(l),ability(a),id(id) {};
 38     bool operator <(const node& r)const
 39     {
 40         return ability<r.ability;
 41     }
 42 } c[maxn];
 43 vector<node>b[maxn];
 44 vector<int>g[maxn];
 45 void build()
 46 {
 47     block = sqrt(n);
 48     num = n / block;
 49     if(n % block) num++;
 50     for(int i = 1; i <= num; i++)
 51     {
 52         l[i] = (i-1)*block+1;
 53         r[i] = i*block;
 54     }
 55     r[num] = n;
 56     for(int i = 1; i <= n; i++)
 57     {
 58         belong[i] = (i-1)/block+1;
 59     }
 60     for(int i = 1; i <= num; i++)
 61     {
 62         for(int j = l[i]; j <= r[i]; j++)
 63         {
 64             int idd = id[j];
 65             c[j] = node(v[idd], a[idd], idd);
 66             b[i].push_back(node(v[idd], a[idd], idd));
 67         }
 68         sort(b[i].begin(), b[i].end());
 69         int len = b[i].size();
 70         maxx[i][len] = -1;
 71         for(int j = len-1; j >= 0; j--)
 72         {
 73             if(maxx[i][j+1] < b[i][j].loyalty)
 74             {
 75                 maxx[i][j] = b[i][j].loyalty;
 76                 p[i][j] = b[i][j].id;
 77             }
 78             else
 79             {
 80                 maxx[i][j] = maxx[i][j+1];
 81                 p[i][j] = p[i][j+1];
 82             }
 83         }
 84     }
 85 }
 86 int query(int fa,int x,int y)
 87 {
 88     int ans=-1,id=-1;
 89     if(belong[x]==belong[y])
 90     {
 91         for(int i=x; i<=y; ++i)
 92         {
 93             if(a[fa]<c[i].ability && ans<c[i].loyalty)
 94             {
 95                 ans=c[i].loyalty;
 96                 id=c[i].id;
 97             }
 98         }
 99     }
100     else
101     {
102         for(int i=x; i<=r[belong[x]]; ++i)
103         {
104             if(a[fa]<c[i].ability && ans<c[i].loyalty)
105             {
106                 ans=c[i].loyalty;
107                 id=c[i].id;
108             }
109         }
110
111         for(int i=belong[x]+1; i<belong[y]; ++i)
112         {
113             int pos = upper_bound(b[i].begin(), b[i].end(), node(0, a[fa], 0)) - b[i].begin();
114             int cur = maxx[i][pos];
115             if(ans < cur)
116             {
117                 ans = cur;
118                 id = p[i][pos];
119             }
120         }
121
122         for(int i=l[belong[y]]; i<=y; ++i)
123         {
124             if(a[fa]<c[i].ability && ans<c[i].loyalty)
125             {
126                 ans=c[i].loyalty;
127                 id=c[i].id;
128             }
129         }
130     }
131     return id;
132 }
133 void init()
134 {
135     for(int i=0; i<=n; ++i)
136     {
137         b[i].clear();
138         g[i].clear();
139     }
140     cnt=0;
141 }
142 void dfs(int root,int fa)
143 {
144     pre[root]=++cnt;
145     id[cnt]=root;
146     int len=g[root].size();
147     for(int i=0; i<len; ++i)
148     {
149         int v=g[root][i];
150         if(v!=fa) dfs(v,root);
151     }
152     last[root]=cnt;
153 }
154 int main()
155 {
156     int t;
157     scanf("%d",&t);
158     while(t--)
159     {
160         scanf("%d%d",&n,&m);
161         init();
162         for(int i=1; i<=n-1; ++i)
163         {
164             int x;
165             scanf("%d%d%d",&x,&v[i],&a[i]);
166             g[x].push_back(i);
167         }
168         dfs(0,0);
169         build();
170         while(m--)
171         {
172             int x;
173             scanf("%d",&x);
174             printf("%d\n",query(x,pre[x],last[x]));
175         }
176     }
177     return 0;
178 }

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11971289.html

时间: 2024-08-29 07:08:06

Successor HDU - 4366 分块的相关文章

HDU 5145 分块 莫队

给定n个数,q个询问[l,r]区间,每次询问该区间的全排列多少种. 数值都是30000规模 首先考虑计算全排列,由于有同种元素存在,相当于每次在len=r-l+1长度的空格随意放入某种元素即$\binom{len}{k_1}$,那么下种元素即为$\binom{len-k_1}{k2}$,以此类推,直至最后直接填满,那么全排列为${\frac{len!}{k_1!k_2!…k_n!}}$ 然后可以发现可以直接O(1)求得左右相邻区间的值(就是乘或除),那么考虑分块莫队. /** @Date : 2

HDU 5213 分块 容斥

给出n个数,给出m个询问,询问 区间[l,r] [u,v],在两个区间内分别取一个数,两个的和为k的对数数量. $k<=2*N$,$n <= 30000$ 发现可以容斥简化一个询问.一个询问的答案为 $[l,v]+(r,u)-[l,u)-(r,v]$,那么我们离线询问,将一个询问分成四个,分块暴力就行了. 然后就是注意细节,不要发生越界,访问错位置之类比较蠢的问题了. /** @Date : 2017-09-24 19:54:55 * @FileName: HDU 5213 分块 容斥.cpp

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

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 h

HDU 4366 Successor 分块做法

http://acm.hdu.edu.cn/showproblem.php?pid=4366 今日重新做了这题的分块,果然是隔太久了,都忘记了.. 首先,用DFS序变成一维的问题 关键是它有两个权值,该如何处理呢? 首先假设我们的DFS序列是List, 那么,对其进行分块.对于每一个块,先按能力排序,用数组tosort[]保存,这样我就可以用O(magic)的时间,就是扫一次这个块,维护出一个数组,mx[i]表示大于等于tosort[i].ablity时,最大的忠诚度. 那么我查询的时候,就可以

HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护

给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示dfs序,则R[i] - L[i] + 1 就是当前i这个节点拥有的子孙个数. 对于一颗树,dfs的时候,访问节点有先后顺序,那么可以用一个struct node List[maxn];表示这课树中访问的先后顺序. 例如这颗树,我假设是先访问0 --> 3 --> 2 ---> 4 ---&g

HDU 4366 Successor

Successor Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 436664-bit integer IO format: %I64d      Java class name: Main Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has

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

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