【BZOJ3531】旅行(SDOI2014)-树链剖分+动态加点线段树
测试地址:旅行
做法:这一题需要用到树链剖分+动态开点线段树。
我们先把树上的问题转到区间上考虑:如何查询一个区间内信某种宗教的所有城市的评级之和或最大值?容易想到的方案是,对于每种宗教建一棵线段树维护,然而这个空间开销实在是太庞大了,无法承受。这个时候就要使用线段树的变体——动态开点线段树。
动态开点线段树这个东西长得有点像主席树,但它们有的时候能解决完全不同的问题。简单的说,动态开点线段树的思想就是:当一个节点被用到时才把这个点建出来。由于题目中的修改只涉及单点修改,所以显然这样做空间和时间都是
那么转到树上就很简单了,直接树链剖分即可。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100000
using namespace std;
int n,q,w[N+10],c[N+10];
int tot=0,first[N+10]={0},totp,tim;
int sum[20*N+10],mx[20*N+10],ch[20*N+10][2];
int fa[N+10],siz[N+10],son[N+10],dep[N+10],top[N+10],pos[N+10];
struct edge
{
int v,next;
}e[2*N+10];
int read()
{
char c;
int ans=0;
c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar();
return ans;
}
void addedge(int a,int b)
{
e[++tot].v=b;
e[tot].next=first[a];
first[a]=tot;
}
void dfs1(int v)
{
siz[v]=1,son[v]=0;
for(int i=first[v];i;i=e[i].next)
if (e[i].v!=fa[v])
{
fa[e[i].v]=v;
dep[e[i].v]=dep[v]+1;
dfs1(e[i].v);
if (siz[e[i].v]>siz[son[v]]) son[v]=e[i].v;
siz[v]+=siz[e[i].v];
}
}
void dfs2(int v,int tp)
{
top[v]=tp;pos[v]=++tim;
if (son[v]) dfs2(son[v],tp);
for(int i=first[v];i;i=e[i].next)
if (e[i].v!=fa[v]&&e[i].v!=son[v])
dfs2(e[i].v,e[i].v);
}
void pushup(int no)
{
sum[no]=sum[ch[no][0]]+sum[ch[no][1]];
mx[no]=max(mx[ch[no][0]],mx[ch[no][1]]);
}
void modify(int &no,int l,int r,int k,int val)
{
if (!no) no=++totp,ch[no][0]=ch[no][1]=0,sum[no]=0;
if (l==r)
{
sum[no]=mx[no]=val;
return;
}
int mid=(l+r)>>1;
if (k<=mid) modify(ch[no][0],l,mid,k,val);
else modify(ch[no][1],mid+1,r,k,val);
pushup(no);
}
int segquery(int no,int l,int r,int s,int t,int mode)
{
if (!no) return 0;
if (l>=s&&r<=t) return mode?mx[no]:sum[no];
int mid=(l+r)>>1,ans=0;
if (!mode)
{
if (s<=mid) ans+=segquery(ch[no][0],l,mid,s,t,mode);
if (t>mid) ans+=segquery(ch[no][1],mid+1,r,s,t,mode);
}
else
{
if (s<=mid) ans=max(ans,segquery(ch[no][0],l,mid,s,t,mode));
if (t>mid) ans=max(ans,segquery(ch[no][1],mid+1,r,s,t,mode));
}
return ans;
}
int query(int x,int y,int mode)
{
int ans=0,C=c[x];
while(top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
if (!mode) ans+=segquery(C,1,n,pos[top[x]],pos[x],mode);
else ans=max(ans,segquery(C,1,n,pos[top[x]],pos[x],mode));
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
if (!mode) ans+=segquery(C,1,n,pos[x],pos[y],mode);
else ans=max(ans,segquery(C,1,n,pos[x],pos[y],mode));
return ans;
}
int main()
{
n=read(),q=read();
for(int i=1;i<=n;i++)
w[i]=read(),c[i]=read();
for(int i=1;i<n;i++)
{
int a,b;
a=read(),b=read();
addedge(a,b),addedge(b,a);
}
fa[1]=siz[0]=dep[1]=0;
dfs1(1);
tim=0;
dfs2(1,1);
sum[0]=mx[0]=0;
for(int i=1;i<=n;i++) ch[i][0]=ch[i][1]=0,sum[i]=0;
totp=n;
for(int i=1;i<=n;i++)
modify(c[i],1,n,pos[i],w[i]);
for(int i=1;i<=q;i++)
{
char op[3];
int x,y;
scanf("%s",op);
x=read(),y=read();
if (op[0]=='C')
{
if (op[1]=='C')
{
modify(c[x],1,n,pos[x],0);
modify(y,1,n,pos[x],w[x]);
c[x]=y;
}
if (op[1]=='W')
{
modify(c[x],1,n,pos[x],y);
w[x]=y;
}
}
if (op[0]=='Q'&&op[1]=='S') printf("%d\n",query(x,y,0));
if (op[0]=='Q'&&op[1]=='M') printf("%d\n",query(x,y,1));
}
return 0;
}