BZOJ 4129 Haruna’s Breakfast ( 树上带修莫队 )

版权声明:本人版权意识薄弱,请随意转载 https://blog.csdn.net/Ike940067893/article/details/88376435

题面

求树上某路径上最小的没出现过的权值,有单点修改 添加链接描述

分析

树上带修莫队板题,问题是怎么求最小的没出现过的权值。
因为只有 n n 个点,所以没出现过的最小值一定在 [ 0 , n ] [0,n] 内,所以大于 n n 的无需维护。那么我们就值域分块,每 n \sqrt n 个数开一个数组,那么从小到大枚举块,如果当前块没有满那么就在这个块里查找,每次查找时间复杂度为 O ( n ) O(\sqrt n) 。因为 n , m n,m 值域相同,所以总时间复杂度为 O ( n 5 3 ( ) + n n ( ) + n l o g n ( ) ) O(n^{\frac 53}(莫队)+n\sqrt n(分块查 询)+nlogn(排序))

  • 我用的是倍增求LCA

CODE

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &num) {
   char ch; while((ch=getchar())<'0'||ch>'9');
   for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
}
const int MAXN = 50005;
int n, m, TreeB, ValB, TIMES, cntq, cntc;
int a[MAXN], la[MAXN], bel[MAXN], ans[MAXN];
struct QUERY {
   int u, v, t, id;
   inline bool operator <(const QUERY &o)const {
   	return bel[u] == bel[o.u] ? (bel[v] == bel[o.v] ? t < o.t : bel[v] < bel[o.v]) : bel[u] < bel[o.u];
   }
}Q[MAXN];
struct CHANGE { int i, u, v; }C[MAXN];
int fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
inline void add(int u, int v) { to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; }
int stk[MAXN], f[MAXN][16], dep[MAXN], dfn[MAXN], tmr, tot, top;

inline void dfs(int u, int ff) {
   int bot = top; dfn[u] = ++tmr;
   dep[u] = dep[f[u][0]=ff] + 1;
   for(int i = fir[u]; i; i = nxt[i])
   	if(to[i] != ff) {
   		dfs(to[i], u);
   		if(top-bot > TreeB) {
   			++tot;
   			while(top > bot) bel[stk[top--]] = tot;
   		}
   	}
   stk[++top] = u;
}

inline void Pre() {
   for(int j = 1; j < 16; ++j)
   	for(int i = 1; i <= n; ++i)
   		f[i][j] = f[f[i][j-1]][j-1];
}

bool vis[MAXN]; int sz[MAXN], val[MAXN];

inline int lca(int u, int v) {
   if(dep[u] < dep[v]) swap(u, v);
   for(int j = 0; j < 16; ++j)
   	if((dep[u]-dep[v])&(1<<j)) u = f[u][j]; 
   if(u == v) return u;
   for(int j = 15; ~j; --j)
   	if(f[u][j] != f[v][j]) u = f[u][j], v = f[v][j];
   return f[u][0];
}

inline void upd(int i) {
   if(!vis[i]) {
   	vis[i] = 1; if(a[i] > n) return;
   	if(++val[a[i]] == 1) ++sz[a[i]/ValB];
   }
   else {
   	vis[i] = 0; if(a[i] > n) return;
   	if(--val[a[i]] == 0) --sz[a[i]/ValB];
   }
}

inline void rev(int u, int v) {
   while(u != v) {
   	if(dep[u] < dep[v]) swap(u, v);
   	upd(u), u = f[u][0];
   }
}
inline void modify(int i, int col) {
   if(!vis[i]) { a[i] = col; return; }
   upd(i), a[i] = col, upd(i);
}
inline int solve() {
   for(int i = 0; ; ++i) if(sz[i] != ValB)
   	for(int j = i*ValB; ; ++j) if(!val[j])
   		return j;
}

int main () {
   read(n), read(m), TreeB = int(pow(n, 0.67)), ValB = int(sqrt(1.0*n));
   for(int i = 1; i <= n; ++i) read(a[i]), la[i] = a[i];
   for(int i = 1, u, v; i < n; ++i) read(u), read(v), add(u, v), add(v, u);
   for(int i = 1, opt, x, y; i <= m; ++i) {
   	read(opt), read(x), read(y);
   	if(!opt) C[++cntc] = (CHANGE){ x, la[x], y }, la[x] = y;
   	else {
   		if(dfn[x] > dfn[y]) swap(x, y);
   		Q[++cntq] = (QUERY){ x, y, cntc, cntq };
   	}
   }
   dfs(1, 0); if(top) ++tot; while(top) bel[stk[top--]] = tot; Pre();
   sort(Q + 1, Q + cntq + 1);
   while(TIMES < Q[1].t) ++TIMES, modify(C[TIMES].i, C[TIMES].v);
   rev(Q[1].u, Q[1].v); int LCA = lca(Q[1].u, Q[1].v);
   upd(LCA), ans[Q[1].id] = solve(), upd(LCA);
   for(int i = 2; i <= cntq; ++i) {
   	while(TIMES < Q[i].t) ++TIMES, modify(C[TIMES].i, C[TIMES].v);
   	while(TIMES > Q[i].t) modify(C[TIMES].i, C[TIMES].u), --TIMES;
   	rev(Q[i-1].u, Q[i].u), rev(Q[i-1].v, Q[i].v), LCA = lca(Q[i].u, Q[i].v);
   	upd(LCA), ans[Q[i].id] = solve(), upd(LCA);
   }
   for(int i = 1; i <= cntq; ++i)
   	printf("%d\n", ans[i]);
   return 0;
}

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/88376435
今日推荐