题目
正解
老势能分析了。
联通块个数等于点数减边数。
用个数据结构维护权值大于等于某个值的点数和边数有多少个。边的权值定义为两边连着的点的点权的最小值。
点权的维护随便搞,重点是边权的维护。
随便定一个根,对于每个点用个set
维护有多少个儿子的权值大于它。
在权值变大的时候,对于父亲边就直接做,对于儿子边,将原来权值大于它,现在权值小于等于它的儿子暴力修改。
势能分析,设势能为每个点的儿子大于它的个数。每次询问,势能顶多加一。
所以时间复杂度为
O
(
(
n
+
q
)
lg
n
)
O((n+q)\lg n)
O((n+q)lgn),后面的这个
lg
n
\lg n
lgn是数据结构的时间复杂度。
代码
实现的时候注意细节,比如什么小于和小于等于之类的。
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;
}