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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章