BZOJ 2588:木会長ツリー上のSpoj 10628.カウント

タイトル

BZOJ 2588

LUOGU 2633

LUOGU SP10628

質問の意味を簡素化:

あなたはn個のノードのツリー、ノード番号を持っている\(1 \ SIMのn \) 各ノードは、量を有しています。次の操作を実行するために必要な:

UVK:シークノードから\(U \ oplus lastans \)をノードAに\(V \)\(K \)軽量。

分析

  1. 右にあるすべての点で、そのランクに右ノードに離散ポイント。
  2. 議長は、各ノードがツリーラインのルートへのパスを、その重量を維持し、ツリーを確立し、その結果、各ノードは、その親の更新を使用することができるので、全体のツリー\(DFS \)再び、その過程で成果。
  3. 解決:使用\(X \)点議長ツリー\(+ Yの\)は、議長ツリーポイント\ - (LCA(X、Y )\) ツリーの会長\( - LCA(X、Y )\) 親ノードを木の会長、この木を見ては、会長生成\(k個\)権限の元のポイントに小さなランキング、最終的な出力を。

コード

#include<bits/stdc++.h>

const int maxn=1e5+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

namespace SGT
{
    struct Orz{int l,r,z;}c[maxn*30];
    int num=0;
    inline void insert(int y,int &x,int l,int r,int p)
    {
        c[x=++num]=c[y];
        ++c[x].z;
        if (l==r) return ;
        int mid=(l+r)>>1;
        if (p<=mid) insert(c[y].l,c[x].l,l,mid,p);
        else insert(c[y].r,c[x].r,mid+1,r,p);
        c[x].z=c[c[x].l].z+c[c[x].r].z;
    }

    inline int query(int x,int y,int z,int d,int l,int r,int k)
    {
        if (l==r) return l;
        int res=c[c[x].l].z+c[c[y].l].z-c[c[z].l].z-c[c[d].l].z;
        int mid=(l+r)>>1;
        if (k<=res) return query(c[x].l,c[y].l,c[z].l,c[d].l,l,mid,k);
        else return query(c[x].r,c[y].r,c[z].r,c[d].r,mid+1,r,k-res);
    }
}

using SGT::insert;
using SGT::query;

int val[maxn],rt[maxn], n,m,tot;
namespace lca
{
    int dep[maxn],f[maxn][21];
    inline void dfs(int x)
    {
        insert(rt[f[x][0]],rt[x],1,tot,val[x]);
        for (int i=1; i<=20; ++i) f[x][i]=f[f[x][i-1]][i-1];
        for (int i=head[x]; i; i=Next[i])
        {
            int y=ver[i];
            if (y==f[x][0]) continue;
            f[y][0]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    }

    inline int LCA(int x,int y)
    {
        if (dep[x]>dep[y]) std::swap(x,y);
        for (int i=20; i>=0; --i)
            if (dep[y]-(1<<i)>=dep[x]) y=f[y][i];
        if (x==y) return x;
        for (int i=20; i>=0; --i)
            if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
}

using namespace lca;

int a[maxn];
int main()
{
    read(n);read(m);
    for (int i=1; i<=n; ++i) read(val[i]),a[i]=val[i];
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    std::sort(a+1,a+n+1);
    tot=std::unique(a+1,a+n+1)-a-1;
    for (int i=1; i<=n; ++i) val[i]=std::upper_bound(a+1,a+tot+1,val[i])-a-1;
    dfs(1);
    int ans=0;
    for (int i=1; i<=m; ++i)
    {
        int x,y,k;
        read(x);read(y);read(k);
        x^=ans;
        int z=LCA(x,y);
        write(ans=a[ query(rt[x],rt[y],rt[z],rt[f[z][0]],1,tot,k) ],'\n');
    }
    IO::flush();
    return 0;
}

おすすめ

転載: www.cnblogs.com/G-hsm/p/11409006.html