終於拿下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 ...