传送门
这题是求固定路径上某固定宗教的评级最大值或和,由于我们知道树上路径是顺着链走的,我们可以用树链剖分使一条链上的编号连续,方便查询。
每个宗教建一棵线段树,动态开点,编号按树链剖分后的新编号,维护的是城市评价。
那么改变评级就相当于改变某线段树内的值,改变宗教就相当于换根(移到另一棵线段树内)。
求值时按链往上跳,统计答案。
Code:
#include
#include
#include
#include
using namespace std;
#define mid (l+r)/2
struct node{int y,next;}a[200010];
int first[100010],w[100010],c[100010];
int rt[100010],total[20000010],maxx[20000010],lc[20000010],rc[20000010];
int fa[100010],dep[100010],son[100010],top[100010],tot[100010],image[100010],fact[100010];
int n,m,d,v,len;
void ins(int x,int y){a[++len]=(node){y,first[x]};first[x]=len;}
void dfs_1(int x)
{
tot[x]=1;
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y!=fa[x])
{
fa[y]=x;
dep[y]=dep[x]+1;
dfs_1(y);
if(tot[y]>tot[son[x]]) son[x]=y;
tot[x]+=tot[y];
}
}
}
void dfs_2(int x,int tp)
{
top[x]=tp;image[x]=++len;fact[len]=x;
if(son[x]) dfs_2(son[x],tp);
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y!=fa[x] && y!=son[x]) dfs_2(y,y);
}
}
void update(int &now,int l,int r)
{
if(!now) now=++len;
total[now]+=d;
if(l==r)
{
maxx[now]=d;
return;
}
if(v<=mid) update(lc[now],l,mid);
else update(rc[now],mid+1,r);
maxx[now]=max(maxx[lc[now]],maxx[rc[now]]);
}
void change_c(int x,int k)
{
v=image[x];d=-w[x];
update(rt[c[x]],1,n);
c[x]=k;d=w[x];
update(rt[c[x]],1,n);
}
void change_w(int x,int k)
{
v=image[x];d=-w[x];
update(rt[c[x]],1,n);
d=w[x]=k;
update(rt[c[x]],1,n);
}
int getsum(int now,int x,int y,int l,int r)
{
if(l==x && r==y) return total[now];
if(y<=mid) return getsum(lc[now],x,y,l,mid);
else if(midreturn getsum(rc[now],x,y,mid+1,r);
else return getsum(lc[now],x,mid,l,mid)+getsum(rc[now],mid+1,y,mid+1,r);
}
void get_sum(int x,int y)
{
int tx=top[x],ty=top[y],ans=0,op=x;
while(tx!=ty)
{
if(dep[tx]>dep[ty]) swap(x,y),swap(tx,ty);
ans+=getsum(rt[c[op]],image[ty],image[y],1,n);
y=fa[ty];ty=top[y];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=getsum(rt[c[op]],image[x],image[y],1,n);
printf("%d\n",ans);
}
int getmax(int now,int x,int y,int l,int r)
{
if(l==x && r==y) return maxx[now];
if(y<=mid) return getmax(lc[now],x,y,l,mid);
else if(midreturn getmax(rc[now],x,y,mid+1,r);
else return max(getmax(lc[now],x,mid,l,mid),getmax(rc[now],mid+1,y,mid+1,r));
}
void get_max(int x,int y)
{
int tx=top[x],ty=top[y],ans=0,op=x;
while(tx!=ty)
{
if(dep[tx]>dep[ty]) swap(x,y),swap(tx,ty);
ans=max(ans,getmax(rt[c[op]],image[ty],image[y],1,n));
y=fa[ty];ty=top[y];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,getmax(rt[c[op]],image[x],image[y],1,n));
printf("%d\n",ans);
}
int main()
{
scanf("%d %d",&n,&m);
memset(first,len=0,sizeof first);
for(int i=1;i<=n;i++) scanf("%d %d",&w[i],&c[i]);
for(int i=1;iint x,y;
scanf("%d %d",&x,&y);
ins(x,y);
ins(y,x);
}
len=0;dep[1]=1;dfs_1(1);
len=0;dfs_2(1,1);
len=0;
for(int i=1;i<=n;i++)
{
v=image[i];d=w[i];
update(rt[c[i]],1,n);
}
for(int i=1;i<=m;i++)
{
char s[10];
int x,y;
scanf("%s %d %d",s,&x,&y);
if(s[1]=='C') change_c(x,y);
if(s[1]=='W') change_w(x,y);
if(s[1]=='S') get_sum(x,y);
if(s[1]=='M') get_max(x,y);
}
}