题目:
传送门
思路:
实际上我们需要解决两个问题
首先,是如何计算评级,
可能会想到前缀和,但是前缀和的修改时间复杂度太高,不能适应需求
接着就想到了树链剖分,无论是修改,还是查询,时间复杂度都是O(n*logn)
接着要解决的就是统计哪一些城市,也就是宗教的问题
在这里,可以针对每一个宗教都建一棵线段树。
具体的统计有点类似LCA
代码:
//树链剖分(貌似并没学),每一个宗教建线段树
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
void read(int &x)
{
x=0;
char c=getchar();
int f=1;
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<0)
{
putchar('-');
write(-x);
return;
}
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
return;
}
int qkpow(int a,int b)
{
if(b==0)
return 1;
if(b==1)
return a;
int t=qkpow(a,b/2);
t*=t;
if(b%2==1)
t*=a;
return t;
}
int n,m;
int tot;
int tot_tre;
int sz;
int w[100005];
int c[100005];
int depth[100005];
int size[100005];
int fa[100005][25];
int bel[100005];
int pos[100005];
int tmax[10000005];
int ts[10000005];
int ls[10000005];
int rs[10000005];
int root[10000005];
int qkpo[25];
int g_next[200005];
int point[200005];
int v[200005];
void add(int x,int y)
{
tot++;
g_next[tot]=point[x];
point[x]=tot;
v[tot]=y;
tot++;
g_next[tot]=point[y];
point[y]=tot;
v[tot]=x;
}
void init(int now,int f,int dep)
{
depth[now]=dep;
size[now]=1;
for(int i=1; i<=17; i++)
{
if(depth[now]-qkpo[i]<0)
break;
fa[now][i]=fa[fa[now][i-1]][i-1];
}
for(int i=point[now];i;i=g_next[i])
if (v[i]!=f)
{
fa[v[i]][0]=now;
init(v[i],now,dep+1);
size[now]+=size[v[i]];
}
}
void dfs(int k,int chain)
{
bel[k]=chain;
pos[k]=++sz;
int l=0;
for(int i=point[k];i;i=g_next[i])
{
if(size[v[i]]>size[l]&&v[i]!=fa[k][0])
l=v[i];
}
if(!l)
return;
dfs(l,chain);
for (int i=point[k];i;i=g_next[i] )
if (v[i]!=l&&v[i]!=fa[k][0])
dfs(v[i],v[i]);
}
void change(int &k,int l,int r,int x,int v)
{
if(!k)
k=++tot_tre;
if(l==r)
{
tmax[k]=ts[k]=v;
return;
}
int mid=(l+r)/2;
if(x<=mid)
change(ls[k],l,mid,x,v);
else
change(rs[k],mid+1,r,x,v);
tmax[k]=max(tmax[ls[k]],tmax[rs[k]]);
ts[k]=ts[ls[k]]+ts[rs[k]];
}
int summ(int k,int l,int r,int ll,int rr)
{
int ans=0;
if(!k)
return 0;
if(ll<=l&&rr>=r)
return ts[k];
int mid=(l+r)/2;
if(ll<=mid)
ans+=summ(ls[k],l,mid,ll,rr);
if(rr>mid)
ans+=summ(rs[k],mid+1,r,ll,rr);
return ans;
}
int maxx(int k,int l,int r,int ll,int rr)
{
int ans=0;
if(!k)
return 0;
if(ll<=l&&rr>=r)
return tmax[k];
int mid=(l+r)/2;
if(ll<=mid)
ans=max(ans,maxx(ls[k],l,mid,ll,rr));
if(rr>mid)
ans=max(ans,maxx(rs[k],mid+1,r,ll,rr));
return ans;
}
int solve_sum(int k,int x,int y)
{
int ans=0;
while(bel[x]!=bel[y])
{
if(depth[bel[x]]<depth[bel[y]])
swap(x,y);
ans+=summ(k,1,n,pos[bel[x]],pos[x]);
x=fa[bel[x]][0];
}
if(depth[x]>depth[y])
swap(x,y);
ans+=summ(k,1,n,pos[x],pos[y]);
return ans;
}
int solve_max(int k,int x,int y)
{
int ans=0;
while(bel[x]!=bel[y])
{
if(depth[bel[x]]<depth[bel[y]])
swap(x,y);
ans=max(ans,maxx(k,1,n,pos[bel[x]],pos[x]));
x=fa[bel[x]][0];
}
if(depth[x]>depth[y])
swap(x,y);
ans=max(ans,maxx(k,1,n,pos[x],pos[y]));
return ans;
}
int main()
{
read(n);
read(m);
for(int i=1;i<=n;i++)
{
read(w[i]);
read(c[i]);
}
for(int i=1;i<n;i++)
{
int s,e;
read(s);
read(e);
add(s,e);
}
qkpo[0]=1;
for(int i=1;i<=17;i++)
qkpo[i]=qkpo[i-1]*2;
init(1,0,1);
dfs(1,1);
for(int i=1;i<=n;i++)
change(root[c[i]],1,n,pos[i],w[i]);
for(int i=1;i<=m;i++)
{
int x,y;
char s[5];
cin>>s>>x>>y;
if(s[1]=='C')
{
change(root[c[x]],1,n,pos[x],0);
c[x]=y;
change(root[c[x]],1,n,pos[x],w[x]);
}
else if(s[1]=='W')
{
change(root[c[x]],1,n,pos[x],y);
w[x]=y;
}
else if(s[1]=='S')
{
write(solve_sum(root[c[x]],x,y));
putchar('\n');
}
else
{
write(solve_max(root[c[x]],x,y));
putchar('\n');
}
}
return 0;
}