传送门
拿到这题,我:树链剖分+线段树!
哎呀C有点大。
动态开点!
不会RE吗…
其实是可能会RE的,为什么呢,我们想,最坏情况是每个点有不同的信仰,那么这个时候我们利用的空间是 n log n n\log n nlogn 当 n n n最坏情况下取 1 0 5 10^5 105时,占用空间是 13.2 × 1 0 5 13.2\times10^5 13.2×105左右,加上修改需要两倍的空间那么应该保险起见线段树需要开27倍左右,但是我看题解里面好像都是开的20倍,有哪位大佬能给我解释一下吗qwq。
开27倍空间也许会MLE,为了保险起见,我用了一个还挺好写的一个优化,就是开一个队列,队列里面存的是之前已经删掉了那些点,当我们要新加入一个点的时候,首先看这个队列里面有没有值,如果有就往那个位置上存,否则就++tot。
大概写出来是这个样子滴:
queue<int> trashcan;
int _new(){
if(trashcan.empty())return ++tot;
int x=trashcan.front();trashcan.pop();
return x;
}
void clear(int u){
seg[u].lc=seg[u].rc=0;
seg[u].sum=seg[u]._max=0;
trashcan.push(u);
}
然后就正常的动态开点维护就可以了
这样开20倍空间就没有问题啦
# include
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
const int N=1e5+5;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int head[N],cnt;
int belief[N],lv[N];
int faz[N],son[N],dep[N],siz[N],top[N],dfn[N],dfx;
int root[N],tot;
queue<int> trashcan;
struct Edge{
int to,next;
}e[N<<1];
void add(int x,int y){
e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}
struct segment_tree{
int lc,rc;
int sum,_max;
}seg[N*20];
void pushup(int u){
seg[u].sum=seg[seg[u].lc].sum+seg[seg[u].rc].sum;
seg[u]._max=max(seg[seg[u].lc]._max,seg[seg[u].rc]._max);
}
int _new(){
if(trashcan.empty())return ++tot;
int x=trashcan.front();trashcan.pop();
return x;
}
void clear(int u){
seg[u].lc=seg[u].rc=0;
seg[u].sum=seg[u]._max=0;
trashcan.push(u);
}
int insert(int u,int l,int r,int x,int k){
if(!u)u=_new();
if(l==r){
seg[u].sum=seg[u]._max=k;
return u;
}
int mid=l+r>>1;
if(x<=mid)seg[u].lc=insert(seg[u].lc,l,mid,x,k);
else seg[u].rc=insert(seg[u].rc,mid+1,r,x,k);
pushup(u);
return u;
}
int erase(int u,int l,int r,int x){
if(l==r){
clear(u);
return 0;
}
int mid=l+r>>1;
if(x<=mid)seg[u].lc=erase(seg[u].lc,l,mid,x);
else seg[u].rc=erase(seg[u].rc,mid+1,r,x);
pushup(u);
if(!seg[u].lc&&!seg[u].rc){
clear(u);
u=0;
}
return u;
}
int Getsum(int u,int l,int r,int ql,int qr){
if(l>=ql&&r<=qr)return seg[u].sum;
int mid=l+r>>1;
int res=0;
if(ql<=mid&&seg[u].lc)res+=Getsum(seg[u].lc,l,mid,ql,qr);
if(qr>mid&&seg[u].rc)res+=Getsum(seg[u].rc,mid+1,r,ql,qr);
return res;
}
int Getmax(int u,int l,int r,int ql,int qr){
if(l>=ql&&r<=qr)return seg[u]._max;
int mid=l+r>>1;
int res=0;
if(ql<=mid&&seg[u].lc)res=max(res,Getmax(seg[u].lc,l,mid,ql,qr));
if(qr>mid&&seg[u].rc)res=max(res,Getmax(seg[u].rc,mid+1,r,ql,qr));
return res;
}
void BeliefModify(int x,int y){
root[belief[x]]=erase(root[belief[x]],1,n,dfn[x]);
belief[x]=y;
root[belief[x]]=insert(root[belief[x]],1,n,dfn[x],lv[x]);
}
void LevelModify(int x,int y){
lv[x]=y;
root[belief[x]]=insert(root[belief[x]],1,n,dfn[x],lv[x]);
}
void RouteQuerySum(int x,int y){
int res=0,be=belief[y];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res+=Getsum(root[be],1,n,dfn[top[x]],dfn[x]);
x=faz[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
res+=Getsum(root[be],1,n,dfn[x],dfn[y]);
printf("%d\n",res);
}
void RouteQueryMax(int x,int y){
int res=0,be=belief[y];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res=max(res,Getmax(root[be],1,n,dfn[top[x]],dfn[x]));
x=faz[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
res=max(res,Getmax(root[be],1,n,dfn[x],dfn[y]));
printf("%d\n",res);
}
void dfs1(int u,int fa){
faz[u]=fa;
siz[u]=1;
dep[u]=dep[fa]+1;
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int _top){
top[u]=_top;
dfn[u]=++dfx;
if(!son[u])return;
dfs2(son[u],_top);
RepG(i,u){
int v=e[i].to;
if(v==faz[u]||v==son[u])continue;
dfs2(v,v);
}
}
int main()
{
memset(head,-1,sizeof(head));
read(n),read(m);
Rep(i,1,n)read(lv[i]),read(belief[i]);
Rep(i,1,n-1){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
dfs1(1,0),dfs2(1,1);
Rep(i,1,n)root[belief[i]]=insert(root[belief[i]],1,n,dfn[i],lv[i]);
Rep(i,1,m){
char opt[10];
int x,y;
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='C')
if(opt[1]=='C')BeliefModify(x,y);
else LevelModify(x,y);
else
if(opt[1]=='S')RouteQuerySum(x,y);
else RouteQueryMax(x,y);
}
return 0;
}