6706. 【2020.06.07省选模拟】tree

题目


正解

老势能分析了。

联通块个数等于点数减边数。
用个数据结构维护权值大于等于某个值的点数和边数有多少个。边的权值定义为两边连着的点的点权的最小值。
点权的维护随便搞,重点是边权的维护。
随便定一个根,对于每个点用个set维护有多少个儿子的权值大于它。
在权值变大的时候,对于父亲边就直接做,对于儿子边,将原来权值大于它,现在权值小于等于它的儿子暴力修改。

势能分析,设势能为每个点的儿子大于它的个数。每次询问,势能顶多加一。
所以时间复杂度为O((n+q)lgn)O((n+q)\lg n),后面的这个lgn\lg n是数据结构的时间复杂度。


代码

实现的时候注意细节,比如什么小于和小于等于之类的。

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define N 500010
#define MX 1000000
int input(){
	char ch=getchar();
	while (ch<'0' || ch>'9')
		ch=getchar();
	int x=0;
	do{
		x=x*10+ch-'0';
		ch=getchar();
	}
	while ('0'<=ch && ch<='9');
	return x;
}
int n;
int h[N];
struct EDGE{
	int to;
	EDGE *las;
} e[N*2];
int ne;
EDGE *last[N];
int fa[N];
void init(int x){
	static int q[N];
	int head=1,tail=1;
	q[1]=x;
	while (head<=tail){
		int x=q[head++];
		for (EDGE *ei=last[x];ei;ei=ei->las)
			if (ei->to!=fa[x]){
				fa[ei->to]=x;
				q[++tail]=ei->to;
			}
	}
}
int td[MX+10],te[MX+10];
void add(int x,int c,int t[]){
	for (;x<=MX;x+=x&-x)
		t[x]+=c;
}
int query(int x,int t[]){
	int r=0;
	for (;x;x-=x&-x)
		r+=t[x];
	return r;
}
struct Num{int x,s;};
bool operator<(Num a,Num b){return a.s<b.s || a.s==b.s && a.x<b.x;}
multiset<Num> s[N];
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=input();
	int Q=input();
	for (int i=1;i<=n;++i){
		h[i]=input();
		add(h[i],1,td);
	}
	for (int i=1;i<n;++i){
		int u=input(),v=input();
		e[ne]={v,last[u]};
		last[u]=e+ne++;
		e[ne]={u,last[v]};
		last[v]=e+ne++;
	}
	init(1);
	for (int i=2;i<=n;++i){
//		printf("%d\n",min(h[i],h[fa[i]]));
		add(min(h[i],h[fa[i]]),1,te);
		if (h[i]>h[fa[i]])
			s[fa[i]].insert({i,h[i]});
	}
//	printf("\n");
	while (Q--){
		int op=input();
		if (op==1){
			int x=input(),y=input();
			add(h[x],-1,td),add(y,1,td);
			auto p=s[x].begin();
			add(h[x],-s[x].size(),te);
			for (auto q=p;p!=s[x].end() && h[p->x]<=y;q=p,++p,s[x].erase(q))
				add(h[p->x],1,te);
			add(y,s[x].size(),te);
			if (h[x]<=h[fa[x]]){
				add(h[x],-1,te);
				if (y>h[fa[x]]){
					add(h[fa[x]],1,te);
					h[x]=y;
					s[fa[x]].insert({x,h[x]});
				}
				else{
					add(y,1,te);
					h[x]=y;
				}
			}
			else{
				s[fa[x]].erase({x,h[x]});
				h[x]=y;
				s[fa[x]].insert({x,h[x]});
			}
		}
		else{
			int y=input();
			printf("%d\n",(query(MX,td)-query(y-1,td))-(query(MX,te)-query(y-1,te)));
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章