Description
题目极不友好
给定一棵有根树(根节点为1),每个点都带有权值,对于点u,其权值设为a[u],其父亲为fa[i]。现有两个函数f1,f2,定义如下:
如果u=1,f1[u]=a[u],f2[u]=1
否则
如果f1[fa[u]]+1 < a[u] f1[u]=a[u],f2[u]=1;
如果f1[fa[u]]+1 > a[u] f1[u]=f1[fa[u]]+1,f2[u]=f2[fa[u]]
如果f1[fa[u]]+1=a[u] f1[u]=f1[fa[u]]+1,f2[u]=f2[fa[u]]+1
现在有两种操作:
0 u val 表示将a[u]改成val
1 u 表示查询f1[u]和f2[u]
对于40%的数据 n<=1000,Q<=1000
对于另外40%的数据 保证这棵树为一条链
对于100%的数据 n<=200000,Q<=200000
Solution
可以发现节点x只会被x到root一条链上的节点影响,f1就是a[x]-dep[x]的最大值,f2则是满足f1的数量。那么树链剖分记录区间最大值和出现次数即可。早上十分zz地写了树状数组套n个set来找各种数字,考完被wife提醒只需要记录最大的就行了。。
可以用bfs求树链剖分所需的dfs序,考虑到每个相邻的同层节点一定相隔了子树size个,那么统计一下就ok
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef std:: pair <int, int> pair;
const int N=800005;
const int E=800005;
struct edge{int x,y,next;}e[E];
int size[N],dep[N],pos[N],fa[N],bl[N];
int max[N*4+1],tot[N*4+1];
int queue[N],mx[N];
int a[N],n;
int ls[N],edCnt;
bool vis[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void addEdge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void bfs(int root) {
int head=1,tail=1; vis[1]=1;
queue[head]=root;
while (head<=tail) {
int now=queue[head++];
for (int i=ls[now];i;i=e[i].next) {
if (vis[e[i].y]) continue;
vis[e[i].y]=1;
dep[e[i].y]=dep[now]+1;
fa[e[i].y]=now;
queue[++tail]=e[i].y;
}
}
drp(ti,n,1) {
int now=queue[ti];
size[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
size[now]+=size[e[i].y];
if (size[e[i].y]>size[mx[now]]) mx[now]=e[i].y;
}
}
bl[1]=1;
rep(ti,1,n) {
int now=queue[ti];
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
if (mx[now]==e[i].y) {
bl[e[i].y]=bl[now];
} else bl[e[i].y]=e[i].y;
}
}
fill(vis,0);
head=1,tail=1; vis[1]=vis[0]=1;
queue[head]=1;
while (head<=tail) {
int now=queue[head++];
if (!vis[mx[now]]) {
vis[mx[now]]=1;
queue[++tail]=mx[now];
}
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]||vis[e[i].y]) continue;
vis[e[i].y]=1;
queue[++tail]=e[i].y;
}
}
int last=1; pos[1]=1;
rep(i,2,n) {
if (fa[queue[i]]!=fa[queue[i-1]]) last=pos[fa[queue[i]]];
else last+=size[queue[i-1]];
pos[queue[i]]=last+1;
}
}
void modify(int now,int tl,int tr,int x,int v) {
if (tl==tr) {
max[now]=v;
tot[now]=1;
return ;
}
int mid=(tl+tr)>>1;
if (x<=mid) modify(now<<1,tl,mid,x,v);
else if (x>mid) modify(now<<1|1,mid+1,tr,x,v);
max[now]=std:: max(max[now<<1],max[now<<1|1]);
tot[now]=tot[now<<1|1];
if (max[now<<1]==max[now<<1|1]) {
tot[now]=tot[now<<1]+tot[now<<1|1];
} else if (max[now<<1]>max[now<<1|1]) tot[now]=tot[now<<1];
}
pair query(int now,int tl,int tr,int l,int r) {
if (tl==l&&tr==r) return pair(max[now],tot[now]);
int mid=(tl+tr)>>1;
if (r<=mid) return query(now<<1,tl,mid,l,r);
else if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
else {
pair qx=query(now<<1,tl,mid,l,mid);
pair qy=query(now<<1|1,mid+1,tr,mid+1,r);
if (qx.first>qy.first) return qx;
else if (qx.first==qy.first) return pair(qx.first,qx.second+qy.second);
else return qy;
}
}
void get_ans(int x) {
int tmp=x;
pair ret=pair(0,0);
while (x!=0) {
pair qx=query(1,1,n,pos[bl[x]],pos[x]);
if (qx.first>ret.first) {
ret=qx;
} else if (qx.first==ret.first) ret.second+=qx.second;
x=fa[bl[x]];
}
printf("%d %d\n", ret.first+dep[tmp], ret.second);
}
int main(void) {
n=read();
rep(i,1,n) a[i]=read();
rep(i,2,n) {
int x=read(),y=read();
addEdge(x,y);
}
bfs(1);
rep(i,1,n) modify(1,1,n,pos[i],a[i]-dep[i]);
int q=read();
while (q--) {
int opt=read(),x=read();
if (opt==0) {
a[x]=read();
modify(1,1,n,pos[x],a[x]-dep[x]);
} else if (opt==1) {
get_ans(x);
}
}
return 0;
}