hihocoder 1193 : 树堆(线段树合并)

传送门

题解:
维护一个 f i 表示父亲节点为 i 的最大值,然后每个子树都有一个DP数组。

发现每次操作是单点查询或者区间加减。 用线段树合并即可。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}
inline void W(int x) {
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int N=1e5+50, L=40;
int n,a[N],b[N],ans[N];
int rt[N],lc[N*L],rc[N*L],tag[N*L],mx[N*L],tot;
vector <int> edge[N];
inline void add(int k,int v) {tag[k]+=v; mx[k]+=v;}
inline void pushdown(int k) {
    if(tag[k]) {
        if(!lc[k]) lc[k]=++tot;
        if(!rc[k]) rc[k]=++tot;
        add(lc[k],tag[k]);
        add(rc[k],tag[k]);
        tag[k]=0;
    }
}
inline void inc(int &k,int l,int r,int L,int R) {
    if(!k) k=++tot;
    if(L<=l && r<=R) {add(k,1); return;}
    pushdown(k); int mid=(l+r)>>1;
    if(R<=mid) inc(lc[k],l,mid,L,R);
    else if(L>mid) inc(rc[k],mid+1,r,L,R);
    else inc(lc[k],l,mid,L,R), inc(rc[k],mid+1,r,L,R);
    mx[k]=max(mx[lc[k]],mx[rc[k]]);
}
inline int ask(int k,int l,int r,int p) {
    if(!k) return 0;
    if(!lc[k] && !rc[k]) return mx[k];
    if(l==r) return mx[k];
    pushdown(k); int mid=(l+r)>>1;
    if(p<=mid) return ask(lc[k],l,mid,p);
    else return ask(rc[k],mid+1,r,p);
}
inline int merge(int x,int y) {
    if(!x) return y;
    if(!y) return x;
    if(!lc[x] && !rc[x]) swap(x,y);
    if(!lc[y] && !rc[y]) {
        add(x,mx[y]);
    } else {
        pushdown(x); pushdown(y);
        lc[x]=merge(lc[x],lc[y]);
        rc[x]=merge(rc[x],rc[y]);
        mx[x]=max(mx[lc[x]],mx[rc[x]]);
    } return x;
}
inline int findr(int k,int l,int r,int val) {
    if(mx[k]<val) {return r+1;}
    if(!lc[k] && !rc[k]) {return l;}
    pushdown(k); int mid=(l+r)>>1;
    if(mx[lc[k]]>=val) return findr(lc[k],l,mid,val);
    else if(mx[rc[k]]>=val) return findr(rc[k],mid+1,r,val);
    return r+1;
}
inline void dfs(int x,int f) {
    for(int e=edge[x].size()-1;e>=0;e--) {
        int v=edge[x][e]; if(v==f) continue;
        dfs(v,x); rt[x]=merge(rt[x],rt[v]);
    } 
    int p=lower_bound(b+1,b+n+1,a[x])-b;
    ans[x]=ask(rt[x],1,n,p)+1;
    int r=findr(rt[x],1,n,ans[x]);
    inc(rt[x],1,n,p,r-1);
}
int main() {
    n=rd();
    for(int i=1;i<=n;i++) a[i]=b[i]=rd();
    sort(b+1,b+n+1);
    for(int i=1;i<n;i++) {
        int x=rd()+1, y=rd()+1;
        edge[x].push_back(y);
        edge[y].push_back(x);
    } dfs(1,0);
    for(int i=1;i<=n;i++) W(ans[i]), putchar(' ');
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/81006956