http://acm.hdu.edu.cn/showproblem.php?pid=4366
题意:给你一棵树,每个结点有两个属性值,1:能力值 2:忠诚度
然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号
做法:
这种题还是老套路,将树形结构转换成线性结构,用数据结构来解决查询最值得问题。
但这个题目有一个亮点就是限制了一个变量,要求另一个变量满足第一个变量大于查询点的同时最大
其实仔细想一下也蛮简单的,将限制的那个变量按要求排序就好了,即从大到小排序,依次将能力大的点先插入线段树
(线段树的话,就是对时间戳建树,dfs时每个点有一个进入的时间戳,还有一个出来的时间戳,这两个时间戳之间的点都属于这个点的子树)
那么就可以在插入当前点之前先询问一下子树内的最大值,即(L[u],R[u])间的最大值 L[u]是进入u子树的时间戳,R[u]是出来的时间戳,这样的话可以处理处所有的点的结果(具体实现的时候要注意L R的边界情况)
然后询问的时候做到O(1)回答
附上一张我dfs时候的时间戳的图,左边的数字表示进去的时候的时间戳,右边的数字表示出来的时候的时间戳
show my code
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
int Max[maxn<<2],ID[maxn<<2];
void pushup(int rt){
if(Max[rt<<1]>Max[rt<<1|1]){
Max[rt]=Max[rt<<1];
ID[rt]=ID[rt<<1];
}
else {
Max[rt]=Max[rt<<1|1];
ID[rt]=ID[rt<<1|1];
}
}
void build(int l,int r,int rt){
Max[rt]=ID[rt]=-1;
if(l==r) return ;
int m=l+r>>1;
build(lson);
build(rson);
}
void update(int pos,int id,int val,int l,int r,int rt){
if(l==r){
ID[rt]=id;
Max[rt]=val;
return ;
}
int m=l+r>>1;
if(pos<=m) update(pos,id,val,lson);
else update(pos,id,val,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L>R) return -1;
if(L<=l&&r<=R){
return Max[rt];
}
int m=(l+r)>>1;
int ret=-1;
if(L<=m) ret=max(ret,query(L,R,lson));
if(R>m) ret=max(ret,query(L,R,rson));
return ret;
}
int L[maxn],R[maxn];
struct node{
int abty;
int loty;
int id;
bool operator < (const node &cmp) const{
return abty>cmp.abty;
}
}in[maxn];
int ans[maxn];
vector<int> edge[maxn];
int tot;
void dfs(int u) {
L[u]=tot++;
int sz=edge[u].size();
for(int i=0;i<sz;i++) {
int v=edge[u][i];
dfs(v);
}
R[u]=tot;
}
map<int,int> mp;
int main() {
int t,n,m;
scanf("%d",&t);
while(t--) {
mp.clear();
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) edge[i].clear();
for(int i=1,fa;i<n;i++) {
scanf("%d%d%d",&fa,&in[i].loty,&in[i].abty);
edge[fa].push_back(i);
in[i].id=i;
mp[in[i].loty]=i;
}
sort(in+1,in+n);
tot=0;
dfs(0);
build(0,tot-1,1);
memset(ans,-1,sizeof(ans));
for(int i=1,j;i<n;i=j) {
j=i;
while(j<n && in[j].abty==in[i].abty) {
int id=in[j].id;
int lo=query(L[id]+1,R[id]-1,0,tot-1,1);
ans[id]= lo==-1 ? -1 :mp[lo];
j++;
}
j=i;
while(j<n && in[j].abty==in[i].abty) {
int id=in[j].id;
update(L[id],id,in[j].loty,0,tot-1,1);
j++;
}
}
int u;
while(m--) {
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return 0;
}
可能会爆栈,要么用c++的方法加栈,要么就直接模拟栈吧。。
#include<cstdio>
#include<vector>
#include<map>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
int Max[maxn<<2],ID[maxn<<2];
void pushup(int rt){
if(Max[rt<<1]>Max[rt<<1|1]){
Max[rt]=Max[rt<<1];
ID[rt]=ID[rt<<1];
}
else {
Max[rt]=Max[rt<<1|1];
ID[rt]=ID[rt<<1|1];
}
}
void build(int l,int r,int rt){
Max[rt]=ID[rt]=-1;
if(l==r) return ;
int m=l+r>>1;
build(lson);
build(rson);
}
void update(int pos,int id,int val,int l,int r,int rt){
if(l==r){
ID[rt]=id;
Max[rt]=val;
return ;
}
int m=l+r>>1;
if(pos<=m) update(pos,id,val,lson);
else update(pos,id,val,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L>R) return -1;
if(L<=l&&r<=R){
return Max[rt];
}
int m=(l+r)>>1;
int ret=-1;
if(L<=m) ret=max(ret,query(L,R,lson));
if(R>m) ret=max(ret,query(L,R,rson));
return ret;
}
int L[maxn],R[maxn];
struct node{
int abty;
int loty;
int id;
bool operator < (const node &cmp) const{
return abty>cmp.abty;
}
}in[maxn];
int ans[maxn];
struct EDGE{
int v,next;
}edge[maxn*2];
int head[maxn];
int E;
int tot;
void add(int a,int b)
{
edge[E].v=b;
edge[E].next=head[a];
head[a]=E++;
}
stack<int> ss;
bool vis[maxn];
void dfs(int root) {
tot=0;
while(!ss.empty()) ss.pop();
ss.push(root);
memset(vis,false,sizeof(vis));
while(!ss.empty())
{
int now=ss.top();
if(!vis[now])
{
L[now]=tot++;
vis[now]=true;
}
bool flag=false;
for(int i=head[now];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].v])
{
flag=true;
ss.push(edge[i].v);
head[now]=edge[i].next;
break;
}
}
if(flag) continue;
if(vis[now])
{
R[now]=tot;
ss.pop();
}
}
}
map<int,int> mp;
int main() {
int t,n,m;
scanf("%d",&t);
while(t--) {
mp.clear();
scanf("%d%d",&n,&m);
fill(head,head+n+1,-1);E=0;
for(int i=1,fa;i<n;i++) {
scanf("%d%d%d",&fa,&in[i].loty,&in[i].abty);
add(fa,i);
in[i].id=i;
mp[in[i].loty]=i;
}
sort(in+1,in+n);
dfs(0);
build(0,tot-1,1);
memset(ans,-1,sizeof(ans));
for(int i=1,j;i<n;i=j) {
j=i;
while(j<n && in[j].abty==in[i].abty) {
int id=in[j].id;
int lo=query(L[id]+1,R[id]-1,0,tot-1,1);
ans[id]= lo==-1 ? -1 :mp[lo];
j++;
}
j=i;
while(j<n && in[j].abty==in[i].abty) {
int id=in[j].id;
update(L[id],id,in[j].loty,0,tot-1,1);
j++;
}
}
int u;
while(m--) {
scanf("%d",&u);
printf("%d\n",ans[u]);
}
}
return 0;
}