1. 程式人生 > >【ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined) D】Tree

【ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined) D】Tree

.... con out contest and urn -- ifdef cnblogs

【鏈接】 我是鏈接,點我呀:)
【題意】


讓你在樹上找一個序列。
這個序列中a[1]=R
然後a[2],a[3]..a[d]它們滿足a[2]是a[1]的祖先,a[3]是a[2]的祖先。。。
且w[a[1]]<=w[a[2]]<=w[a[3]]....
且要求這個序列的長度最長
(且a[1]和a[2]的簡單路徑之間不能有大於等於a[1]的點
(也就是能取就取

【題解】


考慮一個naive的思路。
定義一個next[i]數組,表示i往上最近的權值大於i的節點所在的位置。
則我們每次輸入2 R X的時候
可以從R到next[R],再到next[next[R]]
盡可能地累加和。

獲取最大序列就好。

但顯然會超時。
註意到我們這個next數組最後會把一些節點連在一起。
且越往上的話,權值越大。
則我們可以寫一個樹上倍增。
求出一個f[i][j]
表示i節點往上做2^j次next[i]操作得到的節點是什麽。
以及sum[i][j]
表示i節點往上做2^j次next[i]操作的所有節點的權值和。

輸入1 R W的時候。
看看w[R]是不是大於等於W
是的話f[++cnt][0] = R
否則
在R的f數組中往上走找到第一個權值大於W的節點。
(因為越往上權值越大,顯然有單調性
作為f[++cnt][0]的值。

然後根據f[cnt][0]的值,以及因為cnt上面的節點的f數組都已經求出來了。

所以可以求出f[cnt][0..20]的值了。

再用類似的方法求出sum數組。

求最長路徑的時候,用sum數組和f數組盡量往上走就可以了

註意邊界。
加一些INF的值。
因為可能上面已經沒有大於w的值了。
就會指向0了。

【代碼】

#include <bits/stdc++.h>
#define ll long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define all(x) x.begin(),x.end()
#define pb push_back
#define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1 using namespace std; const double pi = acos(-1); const int dx[4] = {0,0,1,-1}; const int dy[4] = {1,-1,0,0}; const int N = 4e5; const int M = 20; const ll INF = 1e16; int Q; ll last,W[N+10],sum[N+10][M+10]; int f[N+10][M+10],cnt = 1; int main(){ #ifdef LOCAL_DEFINE freopen("rush_in.txt", "r", stdin); #endif ios::sync_with_stdio(0),cin.tie(0); cin >> Q; for (int i = 0;i <= 20;i++) sum[1][i] = sum[0][i] = INF; W[0] = INF; rep1(i,1,Q){ ll ope,p,q; cin >> ope >> p >> q; if (ope==1){ ll R = p^last,w = q^last; cnt++; W[cnt]=w; if (W[R]>=w){ f[cnt][0] = R; }else{ ll now = R; for (int i = 20;i >= 0;i--) if (W[f[now][i]]<w){ now = f[now][i]; } f[cnt][0] = f[now][0]; } for (int i = 1;i <= 20;i++) f[cnt][i] = f[f[cnt][i-1]][i-1]; sum[cnt][0] = W[f[cnt][0]]; for (int i = 1;i <= 20;i++){ if (f[cnt][i]==0) sum[cnt][i] = INF; else sum[cnt][i] = sum[cnt][i-1]+sum[f[cnt][i-1]][i-1]; } }else{ ll R = p^last,X = q^last; int len = 0; if (X<W[R]){ cout<<0<<endl; last=0; continue; } X-=W[R]; len++; for (int i = 20;i >= 0;i--){ if (X>=sum[R][i]){ X-=sum[R][i]; R = f[R][i]; len+=(1<<i); } } cout<<len<<endl; last=len; } } return 0; }

【ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined) D】Tree