「WC2020」有根树(轻重链剖分)

题目

容易发现题目中那个包含 1 1 1的连通块是提示你的,并不是来限制你的。
那么答案一定是 S S S中选择最大的若干个 w w w,剩下的 w w w的最大值 ≤ ∣ S ∣ \leq |S| S
设剩下的 w w w为集合 X X X
考虑一个调整的过程:
如果 ∣ S ∣ < max ⁡ w ∈ X w |S| \lt \max_{w \in X} w S<maxwXw,则选出 max ⁡ w ∈ X w \max_{w \in X} w maxwXw X X X删去后加入 S S S
如果 ∣ S ∣ > max ⁡ w ∈ X w |S| \gt \max_{w\in X} w S>maxwXw并且 min ⁡ w ∈ S w ≤ max ⁡ w ∈ X w \min_{w \in S} w \leq \max_{w \in X} w minwSwmaxwXw,则选出 min ⁡ w ∈ S w \min_{w \in S} w minwSw S S S删去后加入 X X X
并且每次加点删点后只会有一次调整。(但是前提是你不是无脑的把所有点都加入 X X X,如果当前加入的点 w > max ⁡ w ∈ X w w \gt \max_{w \in X} w w>maxwXw的话还是要加入 S S S,否则就无法高效的维护 S S S X X X。)
注意这里我们一定要保证 max ⁡ w ∈ X ≤ min ⁡ w ∈ S \max_{w \in X} \leq \min_{w \in S} maxwXminwS
那么就有一个很简单的 O ( q log ⁡ 2 n ) O(q\log ^2n) O(qlog2n)做法:
线段树维护每个点的 w w w,和每个区间的 max ⁡ w ∈ X w , min ⁡ w ∈ S w \max_{w \in X} w , \min_{w \in S} w maxwXw,minwSw,然后每次调整即可。
注意到我们会有区间加一操作,如果在这次操作之后不满足 max ⁡ w ∈ X ≤ min ⁡ w ∈ S \max_{w \in X} \leq \min_{w \in S} maxwXminwS
那么可以发现一定是(最多只有一个点)加一后达到了 ∣ S ∣ + 1 |S| + 1 S+1,同时 S S S中还有值为 ∣ S ∣ |S| S的元素。
那么只有一个点会违背规则,我们找出这样的一对点,他们分别在 X , S X,S X,S,然后将他们分别在 X , S X,S X,S删除后分别加入 S , X S,X S,X即可。
区间减一请读者自行思考。
使用 z k w zkw zkw线段树即可在 L O J LOJ LOJ上卡过此题。

但是本题还有 O ( n log ⁡ n ) O(n\log n) O(nlogn)做法(没错就是速度最快的前几个那些动辄 7 K B 7KB 7KB的代码)
考虑树链剖分的链加,是难以做到小常数 O ( log ⁡ n ) O(\log n) O(logn)的(不会真的有人想冲一百万的LCT吧?
但是树状数组的单点修改 + + +子树求和可以轻松做到,只是我们不能求全局最小值了。
考虑题目给你的提示, S S S一定是包含根的连通块,所以在一条重链上所有的在 X X X中的点,只有最上面的点有资格作为 max ⁡ w ∈ X w \max_{w \in X} w maxwXw被操作。
S S S同理。
那么我们只维护每条重链上 X / S X/S X/S中深度最小/大的点的 w w w。(用 s e t set set
在这些点被删除被加入的时候我们用树状数组 O ( log ⁡ n ) O(\log n) O(logn)求出他们的 w w w
在一条重链的某个前缀被整体加/减一的时候通过深度判断 X / S X/S X/S中深度最小/大的点的 w w w是否需要加/减一。
那么我们需要一个可以 O ( log ⁡ n ) O(\log n) O(logn)插入, O ( 1 ) O(1) O(1)将一个点找到并且删除并且将他的值加一再插回去, O ( log ⁡ n ) O(\log n) O(logn)求出最大/最小值。
注意到每次只会调整一次,所以求出最大值/最小值可以改为求出 w w w为某个值的点。
实际上直接写双向链表(就是对于每个值开一个链表连着所有值为这个值的点,每次删除可以直接用双向链表删除,记一下位置即可,我在实现的时候使用了 v e c t o r vector vector,插入删除都是 O ( 1 ) O(1) O(1)的)即可。

大数据结构写多了,我已经不会压行了怎么办啊。

A C   C o d e \mathcal AC \ Code AC Code

#include
#define maxn 500005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
#define pb push_back
#define pii pair
#define vc vector
#define vi vc
#define Ct const
#define db double
using namespace std;

namespace IO{
	char cb[1<<16] , *cs=cb,*ct=cb;
	char getc(){ return cs == ct && (ct = (cs = cb) + fread(cb,1,1<<16,stdin),cs == ct) ? 0 : *cs++; }
	template<class T>void read(T &res){
		char ch;bool f=0;
		for(;!isdigit(ch=getc());) if(ch=='-') f = 1;
		for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
		(f) && (res = -res);
	}
};
using IO :: getc;
using IO :: read;

int n,q,ans;
vi G[maxn];
int tp[maxn],son[maxn],sz[maxn],st[maxn],ed[maxn],pos[maxn],fa[maxn],tot;
struct cmp{
	bool operator ()(Ct int &u,Ct int &v)Ct{ return st[u] < st[v]; }
};
set<int,cmp>P[maxn][2];
int W[maxn],B[maxn];

namespace BIT{
	int tr[maxn];
	void upd(int u,int v){ for(;u<=n;u+=u&-u) tr[u] += v;  }
	int qry(int u){ int r=0;for(;u;u-=u&-u) r+=tr[u]; return r; }
};
using BIT::upd;
using BIT::qry;

struct Chains{
	vi G[maxn];
	int loc[maxn];
	
	void ins(int u,int w=-1){
		if(w == -1) w = qry(ed[u]) - qry(st[u] - 1);
		loc[u] = G[w].size();
		G[w].push_back(u);
	}
	void del(int u,int w=-1){
		if(w == -1) w = qry(ed[u]) - qry(st[u] - 1);
		assert(!G[w].empty());
		int t = G[w].back();
		swap(loc[u] , loc[t]);
		swap(G[w][loc[u]] , G[w][loc[t]]);
		G[w].pop_back();
	}
}C[2];

void INS(set<int,cmp>&u,Chains &v,int t){
	if(u.empty()) return;
	int p = (t ? *u.rbegin() : *u.begin());
	v.ins(p,W[p]);
}

void DEL(set<int,cmp>&u,Chains &v,int t){
	if(u.empty()) return;
	int p = (t ? *u.rbegin() : *u.begin());
	v.del(p,W[p]);
}

void dfs0(int u,int ff){
	fa[u] = ff , sz[u] = 1;
	for(int v:G[u]) if(v^ff)
		dfs0(v,u) , sz[u] += sz[v] , (sz[v] > sz[son[u]]) && (son[u] = v);
}

void dfs1(int u,int ff){
	pos[st[u] = ++tot] = u;
	if(son[u]) tp[son[u]] = tp[u] , dfs1(son[u],u);
	for(int v:G[u]) if(v^ff && v ^ son[u])
		dfs1(tp[v] = v,u);
	ed[u] = tot;
}

int main(){
	
	freopen("1.in","r",stdin);
	
	read(n);
	rep(i,1,n-1){
		int u,v;read(u) , read(v);
		G[u].pb(v) , G[v].pb(u);
	}
	dfs0(1,0) , dfs1(tp[1] = 1,0);
	read(q);
	for(int op,u;q--;){
		read(op) , read(u);
		if(op == 1){
			int w = qry(ed[u]) - qry(st[u] - 1);
			if(w <= ans){
				DEL(P[tp[u]][0],C[0],0);
				W[u] = w , B[u] = 0;
				P[tp[u]][0].insert(u);
				INS(P[tp[u]][0],C[0],0);
			}
			else{
				DEL(P[tp[u]][1],C[1],1);
				W[u] = w , B[u] = 1 , ans++;
				P[tp[u]][1].insert(u);
				INS(P[tp[u]][1],C[1],1);
			}
			upd(st[u],1);
		}
		else{
			if(!B[u]){
				DEL(P[tp[u]][0],C[0],0);
				P[tp[u]][0].erase(u);
				if(!P[tp[u]][0].empty()){
					int a = *P[tp[u]][0].begin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][0],C[0],0);
			}
			else{
				DEL(P[tp[u]][1],C[1],1);
				P[tp[u]][1].erase(u);
				if(!P[tp[u]][1].empty()){
					int a = *P[tp[u]][1].rbegin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][1],C[1],1);
				ans --;
			}
			upd(st[u],-1);
		}
		
		for(;u;u=fa[tp[u]]){
			int p = tp[u];
			if(!P[p][0].empty() && st[*P[p][0].begin()] <= st[u]){
				int v = *P[p][0].begin();
				DEL(P[p][0],C[0],0);
				W[v]+=(op == 1 ? 1 : -1);
				INS(P[p][0],C[0],0);
			}
			if(!P[p][1].empty() && st[*P[p][1].rbegin()] <= st[u]){
				int v = *P[p][1].rbegin();
				DEL(P[p][1],C[1],1);
				W[v]+=(op == 1 ? 1 : -1);
				INS(P[p][1],C[1],1);
			}
		}
		
		if(op == 1){
			if(!C[0].G[ans+1].empty() && !C[1].G[ans].empty()){
				int u = C[0].G[ans+1].back() , v = C[1].G[ans].back();
				DEL(P[tp[u]][0],C[0],0);
				DEL(P[tp[u]][1],C[1],1);
				if(tp[v] ^ tp[u])
					DEL(P[tp[v]][1],C[1],1),
					DEL(P[tp[v]][0],C[0],0);
				P[tp[u]][0].erase(u);
				P[tp[u]][1].insert(u);
				P[tp[v]][1].erase(v);
				P[tp[v]][0].insert(v);
				int a = u;
				if(!P[tp[u]][0].empty()){
					a = *P[tp[u]][0].begin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				if(!P[tp[v]][1].empty()){
					a = *P[tp[v]][1].rbegin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][0],C[0],0);
				INS(P[tp[u]][1],C[1],1);
				if(tp[u] ^ tp[v])
					INS(P[tp[v]][1],C[1],1),
					INS(P[tp[v]][0],C[0],0);
				swap(B[u],B[v]);
			}
			
			if(!C[0].G[ans+1].empty()){
				int u = C[0].G[ans+1].back();
				ans++;
				DEL(P[tp[u]][0],C[0],0);
				DEL(P[tp[u]][1],C[1],1);
				P[tp[u]][0].erase(u);
				P[tp[u]][1].insert(u);
				if(!P[tp[u]][0].empty()){
					int a = *P[tp[u]][0].begin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][0],C[0],0);
				INS(P[tp[u]][1],C[1],1);
				B[u] = 1;
			}
			else if(C[0].G[ans].empty()){
				if(ans && !C[1].G[ans-1].empty()) {
					int u = C[1].G[ans-1].back();
					ans--;
					DEL(P[tp[u]][0],C[0],0);
					DEL(P[tp[u]][1],C[1],1);
					P[tp[u]][1].erase(u);
					P[tp[u]][0].insert(u);
					if(!P[tp[u]][1].empty()){
						int a = *P[tp[u]][1].rbegin();
						W[a] = qry(ed[a]) - qry(st[a] - 1);
					}
					INS(P[tp[u]][0],C[0],0);
					INS(P[tp[u]][1],C[1],1);
					B[u] = 0;
				}
			}
		}
		else{
			if(ans && !C[0].G[ans].empty() && !C[1].G[ans-1].empty()){
				int u = C[0].G[ans].back() , v = C[1].G[ans-1].back();
				DEL(P[tp[u]][0],C[0],0);
				DEL(P[tp[u]][1],C[1],1);
				if(tp[u] ^ tp[v])
					DEL(P[tp[v]][1],C[1],1),
					DEL(P[tp[v]][0],C[0],0);
				P[tp[u]][0].erase(u);
				P[tp[u]][1].insert(u);
				P[tp[v]][1].erase(v);
				P[tp[v]][0].insert(v);
				int a = u;
				if(!P[tp[u]][0].empty()){
					a = *P[tp[u]][0].begin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				if(!P[tp[v]][1].empty()){
					a = *P[tp[v]][1].rbegin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][0],C[0],0);
				INS(P[tp[u]][1],C[1],1);
				if(tp[u] ^ tp[v])
					INS(P[tp[v]][1],C[1],1),
					INS(P[tp[v]][0],C[0],0);
				swap(B[u],B[v]);
			}
			if(!C[0].G[ans+1].empty()){
				int u = C[0].G[ans+1].back();
				ans++;
				DEL(P[tp[u]][0],C[0],0);
				DEL(P[tp[u]][1],C[1],1);
				P[tp[u]][0].erase(u);
				P[tp[u]][1].insert(u);
				if(!P[tp[u]][0].empty()){
					int a = *P[tp[u]][0].begin();
					W[a] = qry(ed[a]) - qry(st[a] - 1);
				}
				INS(P[tp[u]][0],C[0],0);
				INS(P[tp[u]][1],C[1],1);
				B[u] = 1;
			}
			else if(C[0].G[ans].empty()){
				if(ans && !C[1].G[ans-1].empty()) {
					int u = C[1].G[ans-1].back();
					ans--;
					DEL(P[tp[u]][0],C[0],0);
					DEL(P[tp[u]][1],C[1],1);
					P[tp[u]][1].erase(u);
					P[tp[u]][0].insert(u);
					if(!P[tp[u]][1].empty()){
						int a = *P[tp[u]][1].rbegin();
						W[a] = qry(ed[a]) - qry(st[a] - 1);
					}
					INS(P[tp[u]][0],C[0],0);
					INS(P[tp[u]][1],C[1],1);
					B[u] = 0;
				}
			}
		}
		printf("%d\n",ans);
	}
}

你可能感兴趣的:(数据结构,码力提高题)