牛客挑戰賽46 F
阿新 • • 發佈:2020-12-15
可以很顯然的發現,答案等於\(\sum{dist_{i,root}}-all(lca(l,l+1,l+2,,,,r))\)其中
我們可以使用線段樹取\([l,r]lca\)。
每一個點到根的和,我們考慮先離線,再\(access\)過程。每一次打通一條鏈,就要把這條鏈上,已經遍歷過的點到該鏈的鏈頭的距離給剪掉。在隨便使用一個數據結構維護字首和單點修改即可。因為離線,儲存R,每一次access後,一定是向後滿足條件的,所以每一次相當於詢問字首是否可行。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #include<unordered_map> #pragma GCC diagnostic error "-std=c++11" #pragma GCC optimize("-fdelete-null-pointer-checks,inline-functions-called-once,-funsafe-loop-optimizations,-fexpensive-optimizations,-foptimize-sibling-calls,-ftree-switch-conversion,-finline-small-functions,inline-small-functions,-frerun-cse-after-loop,-fhoist-adjacent-loads,-findirect-inlining,-freorder-functions,no-stack-protector,-fpartial-inlining,-fsched-interblock,-fcse-follow-jumps,-fcse-skip-blocks,-falign-functions,-fstrict-overflow,-fstrict-aliasing,-fschedule-insns2,-ftree-tail-merge,inline-functions,-fschedule-insns,-freorder-blocks,-fwhole-program,-funroll-loops,-fthread-jumps,-fcrossjumping,-fcaller-saves,-fdevirtualize,-falign-labels,-falign-loops,-falign-jumps,unroll-loops,-fsched-spec,-ffast-math,Ofast,inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2",3) #pragma GCC target("avx","sse2") #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 const int N = 2e5 + 10; int n, Q; vector<int>vec[N]; vector<pir>ques[N]; int dep[N * 2], dfn[N * 2], rk[N * 2], st, dp[N * 2][30]; int ans[N]; struct sgt { int sum[N << 2]; void pushup(int root) { sum[root] = sum[lrt] + sum[rrt]; } void update(int l, int r, int root, int pos, int val) { if (l == r) { sum[root] += val; return; } int mid = (l + r) >> 1; if (pos <= mid)update(lson, pos, val); else update(rson, pos, val); pushup(root); } int query(int l, int r, int root, int lf, int rt) { if (lf > rt)return 0; if (lf <= l && r <= rt) { return sum[root]; } int mid = (l + r) >> 1; int ans = 0; if (lf <= mid)ans += query(lson, lf, rt); if (rt > mid)ans += query(rson, lf, rt); return ans; } }T; struct LCT { int ch[N][2], par[N], lz[N], val[N], sz[N]; int ident(int rt, int fa) { return ch[fa][1] == rt; } void connect(int rt, int fa, int son) { par[rt] = fa; ch[fa][son] = rt; } bool isroot(int rt) { int f = par[rt]; return ch[f][1] != rt && ch[f][0] != rt; } void rotate(int rt) { int f = par[rt]; int ff = par[f]; int k = ident(rt, f); connect(ch[rt][k ^ 1], f, k); par[rt] = ff; if (!isroot(f))ch[ff][ident(f, ff)] = rt; connect(f, rt, k ^ 1); pushup(f); pushup(rt); } void pushup(int rt) { sz[rt] = sz[ch[rt][0]] + sz[ch[rt][1]] + 1; } void pushdown(int rt) { if (lz[rt]) { int ls = ch[rt][0]; int rs = ch[rt][1]; if (ls)val[ls] = lz[ls] = lz[rt]; if (rs)val[rs] = lz[rs] = lz[rt]; lz[rt] = 0; } } void pushall(int rt) { if (!isroot(rt))pushall(par[rt]); pushdown(rt); } void splay(int x) { pushall(x); while (!isroot(x)) { int f = par[x]; int ff = par[f]; if (!isroot(f))ident(f, ff) ^ ident(x, f) ? rotate(x) : rotate(f); rotate(x); } } void access(int x, int col) { int y; for (y = 0; x; y = x, x = par[x]) { splay(x); if (val[x]) T.update(1, n, 1, val[x], -sz[ch[x][0]] - 1); T.update(1, n, 1, col, sz[ch[x][0]] + 1); //cout <<val[x]<<" "<< T.query(1, n, 1, 1, val[x]) << " "; ch[x][1] = y; pushup(x); } val[y] = lz[y] = col; } }lct; void dfs1(int u, int fa, int d) { lct.par[u] = fa; dfn[++st] = u; dep[st] = d; rk[u] = st; for (auto k : vec[u]) { if (k == fa)continue; dfs1(k, u, d + 1); dfn[++st] = u; dep[st] = d; rk[u] = st; } } void initst() { upd(i, 0, 2 * n)dp[i][0] = i; upd(j, 1, 30) { for (int i = 1; i + (1 << j) - 1 <= 2 * n; i++) { int t1 = dp[i][j - 1]; int t2 = dp[i + (1 << (j - 1))][j - 1]; dp[i][j] = dep[t1] < dep[t2] ? t1 : t2; } } } int lca(int x, int y) { x = rk[x], y = rk[y]; if (x > y)swap(x, y); int k = int(log2(y - x + 1)); int t1 = dp[x][k]; int t2 = dp[y - (1 << k) + 1][k]; return dep[t1] < dep[t2] ? dfn[t1] : dfn[t2]; } struct LCAT { int LCA[N << 2]; void pushup(int root) { LCA[root] = lca(LCA[lrt], LCA[rrt]); } void build(int l, int r, int root) { if (l == r) { LCA[root] = l; return; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(root); } int query(int l, int r, int root, int lf, int rt) { if (lf <= l && r <= rt) { return LCA[root]; } int mid = (l + r) >> 1; int temp = -1; if (lf <= mid)temp = query(lson, lf, rt); if (rt > mid) { if (temp == -1)temp = query(rson, lf, rt); else temp = lca(temp, query(rson, lf, rt)); } return temp; } }LCAT; int main() { n = read(); Q = read(); int u, v; upd(i, 1, n - 1) { u = read(), v = read(); vec[u].push_back(v); vec[v].push_back(u); } upd(i, 1, Q) { u = read(), v = read(); ques[v].push_back({ u,i }); } dfs1(1, 0, 0); initst(); upd(i, 1, n) { lct.sz[i] = 1; } LCAT.build(1, n, 1); //cout << LCAT.query(1, n, 1, 1, 2); upd(i, 1, n) { lct.access(i, i); ////cout << T.query(1, n, 1, 1, i); //upd(j, 1, i) { // cout << T.query(1, n, 1, 1, j) << " "; //}cout << endl; for (auto k : ques[i]) { ans[k.second] = T.query(1, n, 1, k.first, i) - dep[rk[LCAT.query(1, n, 1, k.first, i)]] - 1; } } upd(i, 1, Q)printf("%d\n", ans[i]); return 0; }