天天愛跑步

2022-05-16 03:17:27 字數 2878 閱讀 6892

終於拿下noip最難一題

看別人的題解看不懂

於是準備寫一篇更通俗易懂雜亂無章的題解

樹上差分+線段樹(桶)+lca

將每條路徑在lca處切成上公升路徑和下降路徑

會發現對於x號觀察員若觀察到玩家i

則必有dep[i]=w[x]+depx

或dep[i]-2*dep[lca]=w[x]-depx

我們用桶標記(桶用動態開點線段樹實現)

具體實現:

用兩種線段樹統計 第一種統計上公升段 第二種統計下降段

若乙個玩家從s到t點 記l=lca(s,t)

則在s節點加上上公升段該值標記(dep[s])

在t節點加上下降段該值標記(dep[s]-2dep[l])

則為了避免在l處統計兩次

下降段在l處刪除上述標記(dep[s]-2dep[l])

上公升段在l的父親處刪除上述標記(dep[s])

然後一遍dfs

對於每個點x

將其子節點的線段樹都合併起來

並加上/刪去該點的標記值

對於上公升段的線段樹

求w[i]-dep[x]的次數

對於下降段的線段樹

求w[i]+dep[x]的次數

最後x點答案即為上面兩次求的答案之和

總複雜度 o(\(n\log n\))

200行** 還好沒出禍。。。

#include#include#include#include#include#include#include#include#define inf 2000000000

#define min(x,y) ((x)<(y)?(x):(y))

#define max(x,y) ((x)>(y)?(x):(y))

#define rep(i,a,b) for(int i=(a);i<=(b);++i)

#define dwn(i,a,b) for(int i=(a);i>=(b);--i)

using namespace std;

typedef long long ll;

int n,m,root=1,a[300010];

int dep[300010],f[300010][20],lg2[300010];

int tot=1,head[300010];

queueque;

int tot1=0,rt1[300010],up[6000010],ul[6000010],ur[6000010];

int tot2=0,rt2[300010],dn[6000010],dl[6000010],dr[6000010];

vectoradd1[300010],add2[300010],del1[300010],del2[300010];

int ans[300010];

struct edge

edge[600010];

void adde(int u,int v)

int read()

return x;

}void bfs()

que.push(y);}}

}int lca(int x,int y)

void adup(int &k,int l,int r,int x,int d)

int mid=(l+r)>>1;

if(x<=mid) adup(ul[k],l,mid,x,d);

else adup(ur[k],mid+1,r,x,d);

up[k]=up[ul[k]]+up[ur[k]];

}void addn(int &k,int l,int r,int x,int d)

int mid=(l+r)>>1;

if(x<=mid) addn(dl[k],l,mid,x,d);

else addn(dr[k],mid+1,r,x,d);

dn[k]=dn[dl[k]]+dn[dr[k]];

}int askup(int &k,int l,int r,int x)

int mid=(l+r)>>1;

if(x<=mid) return askup(ul[k],l,mid,x);

else return askup(ur[k],mid+1,r,x);

}int askdn(int &k,int l,int r,int x)

int mid=(l+r)>>1;

if(x<=mid) return askdn(dl[k],l,mid,x);

else return askdn(dr[k],mid+1,r,x);

}int mergeup(int p,int q,int l,int r)

int mid=(l+r)>>1;

ul[p]=mergeup(ul[p],ul[q],l,mid);

ur[p]=mergeup(ur[p],ur[q],mid+1,r);

up[p]=up[ul[p]]+up[ur[p]];

return p;

}int mergedn(int p,int q,int l,int r)

int mid=(l+r)>>1;

dl[p]=mergedn(dl[p],dl[q],l,mid);

dr[p]=mergedn(dr[p],dr[q],mid+1,r);

dn[p]=dn[dl[p]]+dn[dr[p]];

return p;

}void dfs(int x)

for(int i=0;i>1]+1;

rep(i,1,n-1)

rep(i,1,n) a[i]=read();

bfs();

rep(i,1,m)

dfs(root);

rep(i,1,n)

return 0;

}

跑步愛天天

對於 50 的資料 直接模擬 對於另外10 的資料 因為地圖是一條鏈,顯然 yousiki 會消滅所有距離他為偶數條邊的祖 先。對於100 的資料 我們先把整個樹 dfs 一遍,遇到乙個點就把這個點記錄到乙個陣列後邊,即求出了樹的尤拉序,顯然如果不考慮迴圈的話,guard是在這個序列上每次往後走乙個...

天天愛跑步

一道 樹上差分 lca 桶的題 說實話,這道題放在d1t2就是非常不合理的。然而ccf就是放了,並且還是能依靠csp撈錢,你也必須交錢參加比賽。這個社會是多麼的不公啊!閒扯結束 顯然如果對每條路徑都進行一次處理,複雜度不對。考慮對路徑進行一次預處理,然後進行統一的計算答案。我們發現當一條路徑對某乙個...

天天愛跑步

暴力程式 25pts 複雜度 o n 2 includeusing namespace std const int maxn 3e5 10 int n,m,ans maxn inline int read while c 0 c 9 return x f int beg maxn nex maxn ...