[牛オフチャレンジ32E]ツリーを逆にします

タイトル

データ範囲は非常に奇妙である、逆の数を求める\(k個の\のLeq 30000 \) 我々はすべての状況を知ることができるはずです

2つのツリーが見つかり\(X、Y \)の場合、\(X \)がある\(Y \)祖先の、次に大きい絶対値のシンボル点は、逆の形成か否かを判断します

場合は\(A_X> A_Y \) 否定しませ\(A_Xは\) その後、関係なくの\(A_Yの\は)否定かどうか、確かに理由は、逆の順序を形成します\(A_X> A_Y> -a_y \) ;もしに対し、否定\(A_X \)その後に関係なくの、\(A_Yは\)否定かないので、確かに、逆の順序を形成していない\(A_Y> -a_y> -a_x \ )

そこで、回答の点への寄与は、ツリーの添加の順序次に、絶対値に応じて、小から大への順序付きサブツリーは、その内部の点の数よりも少ないプラスルートへのパスは、その点の数よりも大きいこと。我々はポイント追加したとき\(X \)を非反転場合、次いでルートへのパスは、明らかに、その内部よりも少し大きくなく、そのサブツリーは、多数のその逆サブツリーの内側に全てより少ない形成されています点の数、ネゲート、次いで、ルートへのパスが、内側のサブツリーよりも若干小さく、すべてのその点以下である場合、それは数のルートフォームへのパス上のポイントの数と逆であります

だから、ビットを求めて木のクロス+フェンウィックツリーは、その後、十分にそらすためにバックパックに従事し、バックパックはする必要があります(\ RMビットセット\)\最適化を

複雑\(O(N ^ログ\ \){W} 2N + \ FRAC {NKを})

コード

#include<bits/stdc++.h>
#define re register
#define LL long long
#define lb(i) (i&-i)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
struct E{int v,nxt;}e[maxn<<1];
struct pt{int x,id;}a[maxn];
std::bitset<300001> dp;
int n,num,Q,c[maxn],__;
int sum[maxn],dfn[maxn],top[maxn],fa[maxn],head[maxn],deep[maxn],son[maxn];
inline int cmp(pt A,pt B) {return A.x<B.x;}
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
inline void ins(int x) {
    for(re int i=x;i<=n;i+=lb(i)) c[i]++;
}
inline int ask(int x) {
    int now=0;
    for(re int i=x;i;i-=lb(i)) now+=c[i];
    return now;
}
inline int calc(int l,int r) {return ask(r)-ask(l-1);}
inline int get(int x) {
    int now=0;
    while(top[x]) now+=calc(dfn[top[x]],dfn[x]),x=fa[top[x]];
    return now;
}
void dfs1(int x) {
    sum[x]=1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(deep[e[i].v]) continue;
        deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
        dfs1(e[i].v),sum[x]+=sum[e[i].v];
        if(sum[e[i].v]>sum[son[x]]) son[x]=e[i].v;
    }
}
void dfs2(int x,int topf) {
    top[x]=topf,dfn[x]=++__;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(re int i=head[x];i;i=e[i].nxt)
    if(!top[e[i].v]) dfs2(e[i].v,e[i].v);
}
int main() {
    n=read();
    for(re int i=1;i<=n;i++) a[i].x=read(),a[i].id=i;
    for(re int x,y,i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
    deep[1]=1,dfs1(1),dfs2(1,1);
    std::sort(a+1,a+n+1,cmp);
    dp[0]=1;
    for(re int i=1;i<=n;i++) {
        int x=calc(dfn[a[i].id],dfn[a[i].id]+sum[a[i].id]-1),y=get(a[i].id);
        dp=(dp<<x)|(dp<<y);ins(dfn[a[i].id]);
    }
    Q=read();while(Q--) puts(dp[read()]?"Orz":"QAQ");
    return 0;
}

おすすめ

転載: www.cnblogs.com/asuldb/p/11566025.html