Codechefは子供のツアーをTRIPS(ブロック、乗算)

トピックへのリンク:https://www.codechef.com/problems/TRIPS

CCは少し悪性腫瘍ああを感じています。

ソリューション:まず、プロパティがあるが説明するので、誰がオンラインあまりにも愚かなことかもしれないが、私は長い間見た:正であり、同じ時間に、同じ期間を経てパスを逆転します。(あなたはこのような性質を考えた場合、明らかに私の証拠を見ていません。)

証明:まず、以下の手順を検討し、その一部がよさそう理解する:1 1 1 2 1 1 1 2 1 1 1 2 1 1 1 2 1 1 1 2、物理的な\(P = 6 \)

正のシーケンスでは\(1,2,3,4,5 \)日が離れて歩いた後されている(5,10,15,19,20 \)\、それぞれ左端、一日を、1(\ 6,11,16,20 \) このシーケンスが示されている\(SA \)

逆に\(1,2,3,4,5 \)はそれぞれ離れて歩く日後\(4,8,12,16,20 \) それぞれ最左位置、一日\(17、13、 9,5,1 \)ように、この配列は逆に反転されているので、(1,5,9,13,17 \)\、このシーケンスが示されている\(SB \)を

その後、我々は道、そして最初の「主要な」リバースフリップ開始位置を後日より各シーケンス天元の開始位置として見ることができます\(私は\)で示さ離れ有数日を\(T(I)= SA [i]は-sb [I] \)

明らかに\(T(1)-T( I-1)\) される(0 \)\または\(1 \)として\(1 \)のみ正のシーケンスその日場合残存体力が下降されていないことを場合その日の強さの残りの部分。

そこでいったん\(k個\)を満たすには、\(SA [K] = SB [K + 1] \) それが最初のことを意味\(K \)先に逆よりも一日の旅の天元順序、そして答えを逆に正シーケンス同じではありません。

そこに、最小を見つけることを想定\(K \)を、次いで\(SA [-K 1] SB = [K] -1 \) すなわちで\((K-1)\ ) tianzheng配列は「不良を有しますステップ「(すなわち、逆方向到達する最初の順序を逆に一日もたらす\(k個の\)左端位置日)、したがって((K-1)= 1 \ T(k)-t)\。最初逆\を( K \)日でなければならない(2 \)\残り遮断\(1 \)物理的、及びこの\(2 \に)最初に必ず次の日、\ \((K-1) )に行く日第一縁(右端)。そして、理由は最初の\((K-1)\ ) の日「より多くのステップが逆の順序で到着予定の正のシーケンスの左端の位置\(k個\)左端日」、その最初の\((K-1)\ ) tianzheng配列は逆の左端の位置に等しい\((K-1)\ ) 右端日。したがって、第1の正のシーケンス\((K-1)\ ) 支配左端値である\(2 \) この位置が設定されている\(POS \)

\(k個\)左端の日は、この位置で次のようである(POS + 1 \)\。最初に考えてみましょう(\(K-1)\を ) 一日の大半のための正のシーケンスでは、日最初の逆順キャッチする権利位置\(k個の\)日の右端位置は、正のシーケンスは逆よりもマルチポジションでなければならない歩い\(POS \)および\(posが\)重み付けされ(2 \)を\します、正シーケンス比逆転する手段行く\(2 \)を明らかに達成することができない、離れて。矛盾が、そうそのような存在しない\(K \)

このようなものは、私は本当に長い時間のために考えて、説明するのは本当に難しいです......

私たちは、比較的単純な背後にある自然だけでなく、そのシンプルな推論を発見しました

ブロック議論

以下のために(P> \ sqrtのN \) \の問い合わせ、暴力はジャンプジャンプアップするために倍増(\ sqrtのN \)\を回。

(P \ル\ SQRT N \ )\ 、プレスの問い合わせ\(P \)大に、わずかから()O(\ SQRT N \ \) 異なる\(P \) 前処理のそれぞれについてアレイ([I] [J Fは\ ] \) を表し\(iは\)までジャンプポイント\(2 ^ j個の\)日(ステップではない)場合にジャンプする、暴力について問い合わせにジャンプします

時間複雑\(O(nは\ sqrtのn個 \ログN)\)

そして、このような大型の複雑さにもかかわらず、時間を測定するCCの上にある\(3.42s \) 制限時間\(8S \) )。

コード

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
#include<cmath>
using namespace std;

const int N = 1e5;
const int MXB = 317;
const int LGN = 16;
struct Edge
{
    int v,w,nxt;
} e[(N<<1)+3];
struct Query
{
    int u,v,p,id;
    bool operator <(const Query &arg) const
    {
        return p<arg.p;
    }
} qr[N+3];
int fe[N+3];
int fa[N+3][LGN+3];
int dep[N+3],dis[N+3];
int f[N+3][LGN+3];
int ans[N+3];
int n,q,en,B;

void addedge(int u,int v,int w)
{
    en++; e[en].v = v; e[en].w = w;
    e[en].nxt = fe[u]; fe[u] = en;
}

void dfs(int u)
{\
    for(int i=1; i<=LGN; i++) fa[u][i] = fa[fa[u][i-1]][i-1];
    for(int i=fe[u]; i; i=e[i].nxt)
    {
        int v = e[i].v;
        if(v==fa[u][0]) continue;
        fa[v][0] = u;
        dep[v] = dep[u]+1; dis[v] = dis[u]+e[i].w;
        dfs(v);
    }
}

int LCA(int u,int v)
{
    if(dep[u]<dep[v]) {swap(u,v);}
    int dif = dep[u]-dep[v];
    for(int i=0; i<=LGN; i++) {if(dif&(1<<i)) u = fa[u][i];}
    if(u==v) return u;
    for(int i=LGN; i>=0; i--)
    {
        if(fa[u][i]!=fa[v][i]) {u = fa[u][i],v = fa[v][i];}
    }
    return fa[u][0];
}

int jump0(int u,int p)
{
    int tdis = dis[u];
    for(int i=LGN; i>=0; i--)
    {
        if(fa[u][i]!=0 && tdis-dis[fa[u][i]]<=p) {u = fa[u][i];}
    }
    return u;
}

int jump_large(int &u,int lca,int p)
{
    int ret = 0;
    while(dis[u]-dis[lca]>=p)
    {
        u = jump0(u,p);
        ret++;
    }
    return ret;
}

int solve_large(int u,int v,int p)
{
    int ret = 0; int lca = LCA(u,v);
    int ret1 = jump_large(u,lca,p),ret2 = jump_large(v,lca,p);
    ret = ret1+ret2;
//  printf("u=%d v=%d\n",u,v);
    if(u==lca && v==lca);
    else if(dis[u]+dis[v]-2*dis[lca]<=p) ret++;
    else ret+=2;
    return ret;
}

int jump_small(int &u,int lca,int p)
{
    int ret = 0;
    for(int i=LGN; i>=0; i--)
    {
        if(dis[f[u][i]]>dis[lca]) {u = f[u][i]; ret += (1<<i);} //> not >= 
    }
    return ret;
}

int solve_small(int u,int v,int p)
{
    int ret = 0; int lca = LCA(u,v);
    int ret1 = jump_small(u,lca,p),ret2 = jump_small(v,lca,p);
    ret = ret1+ret2;
//  printf("u=%d v=%d lca%d ret1=%d ret2=%d\n",u,v,lca,ret1,ret2);
    if(u==lca && v==lca);
    else if(dis[u]+dis[v]-2*dis[lca]<=p) ret++;
    else ret+=2;
    return ret;
}

int main()
{
    scanf("%d",&n); B = sqrt(n);
    for(int i=1; i<n; i++)
    {
        int x,y,z; scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z); addedge(y,x,z);
    }
    dep[1] = dis[1] = 1; dfs(1);
    scanf("%d",&q);
    for(int i=1; i<=q; i++)
    {
        int u,v,p; scanf("%d%d%d",&qr[i].u,&qr[i].v,&qr[i].p); qr[i].id = i;
    }
    sort(qr+1,qr+q+1);
    for(int i=1; i<=n; i++) f[i][0] = fa[i][0];
    int id = 0;
    for(int i=2; i<=B; i++)
    {
        for(int j=2; j<=n; j++)
        {
            if(dis[j]-dis[fa[f[j][0]][0]]<=i) {f[j][0] = fa[f[j][0]][0];}
        }
        for(int j=1; j<=LGN; j++)
        {
            for(int k=1; k<=n; k++) f[k][j] = f[f[k][j-1]][j-1];
        }
        while(id<q && qr[id+1].p==i)
        {
            id++;
            ans[qr[id].id] = solve_small(qr[id].u,qr[id].v,qr[id].p);
        }
    }
    for(id=id+1; id<=q; id++)
    {
        ans[qr[id].id] = solve_large(qr[id].u,qr[id].v,qr[id].p);
    }
    for(int i=1; i<=q; i++) printf("%d\n",ans[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11105116.html