[BZOJ 3531]旅行
发现自己好久没写树链剖分了……唉……
言归正传,这道题很容易想到的做法就是每种宗教开一个线段树,到各个宗教的线段树里面操作即可。
很可惜,直接开线段树的话肯定会MLE。我们可以考虑动态开点,对于不需要的点一律不开。这样内存消耗量就大减了。
注意一些细节:
- 查询时判断当前结点是不是NULL。
- 删除前最好判断一下这个结点是不是NULL吧,以防万一。
- 删除操作时,如果结点没有用了,就删。但是注意,记得delete前要把原指针设为NULL,直接delete会引起悬垂指针问题导致爆炸!
代码:
/**************************************************************
Problem: 3531
User: danihao123
Language: C++
Result: Accepted
Time:10404 ms
Memory:34872 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100005;
int n;
namespace SegmentTree{
struct Node{
int sumv,maxv;
Node *lc,*rc;
Node(){
sumv=maxv=0;
lc=rc=NULL;
}
void maintain(){
if(lc!=NULL){
if(rc!=NULL){
sumv=lc->sumv+rc->sumv;
maxv=max(lc->maxv,rc->maxv);
}else{
sumv=lc->sumv;
maxv=lc->maxv;
}
}else{
if(rc!=NULL){
sumv=rc->sumv;
maxv=rc->maxv;
}
}
}
};
Node* T[maxn];
int p,v;
void _Delete(Node* &o,int L,int R){
if(o==NULL)
return;
if(L==R){
Node *temp=o;
o=NULL;
delete temp;
}else{
int M=L+(R-L)/2;
if(p<=M)
_Delete(o->lc,L,M);
else
_Delete(o->rc,M+1,R);
if(o->lc==NULL && o->rc==NULL){
Node *temp=o;
o=NULL;
delete temp;
}else{
o->maintain();
}
}
}
inline void Delete(int c,int pos){
p=pos;
_Delete(T[c],1,n);
}
void _Insert(Node* &o,int L,int R){
if(o==NULL)
o=new Node();
if(L==R){
o->sumv=o->maxv=v;
}else{
int M=L+(R-L)/2;
if(p<=M)
_Insert(o->lc,L,M);
else
_Insert(o->rc,M+1,R);
}
o->maintain();
}
inline void Insert(int c,int pos,int value){
p=pos;
v=value;
_Insert(T[c],1,n);
}
int ql,qr;
int _query_max(Node *o,int L,int R){
if(o==NULL)
return 0;
if(ql<=L && R<=qr)
return o->maxv;
int M=L+(R-L)/2,ans=0;
if(ql<=M)
ans=max(ans,_query_max(o->lc,L,M));
if(qr>M)
ans=max(ans,_query_max(o->rc,M+1,R));
return ans;
}
inline int query_max(int c,int l,int r){
ql=l;
qr=r;
return _query_max(T[c],1,n);
}
int _query_sum(Node *o,int L,int R){
if(o==NULL)
return 0;
if(ql<=L && R<=qr)
return o->sumv;
int M=L+(R-L)/2,ans=0;
if(ql<=M)
ans+=_query_sum(o->lc,L,M);
if(qr>M)
ans+=_query_sum(o->rc,M+1,R);
return ans;
}
inline int query_sum(int c,int l,int r){
ql=l;
qr=r;
return _query_sum(T[c],1,n);
}
};
#define REP(i,n) for(i=0;i<(n);i++)
#define REP_B(i,n) for(i=1;i<=(n);i++)
#define GRAPH_REP(i,u) for(i=first[(u)];i;i=next[i])
int first[maxn];
int next[maxn*2],to[maxn*2];
int graph_tot=0;
inline void AddEdge(int u,int v){
graph_tot++;
next[graph_tot]=first[u];
first[u]=graph_tot;
to[graph_tot]=v;
}
int dep[maxn],fa[maxn],son[maxn],siz[maxn];
bool vis[maxn];
void dfs_1(int x,int father,int depth){
vis[x]=true;
fa[x]=father;
dep[x]=depth;
siz[x]=1;
int i,temp,max_siz=0;
GRAPH_REP(i,x){
temp=to[i];
if(!vis[temp]){
dfs_1(temp,x,depth+1);
siz[x]+=siz[temp];
if(siz[temp]>max_siz){
son[x]=temp;
max_siz=siz[temp];
}
}
}
}
int hld_cnt=0;
int rlg[maxn];
int d[maxn];
int tid[maxn],top[maxn];
void dfs_2(int x,int a){
vis[x]=true;
top[x]=a;
tid[x]=++hld_cnt;
SegmentTree::Insert(rlg[x],hld_cnt,d[x]);
if(son[x])
dfs_2(son[x],a);
else
return;
int i,temp;
GRAPH_REP(i,x){
temp=to[i];
if(!vis[temp]){
dfs_2(temp,temp);
}
}
}
int query_max(int c,int x,int y){
if(top[x]==top[y]){
if(tid[x]>tid[y])
swap(x,y);
return SegmentTree::query_max(c,tid[x],tid[y]);
}
if(dep[top[x]]<dep[top[y]])
swap(x,y);
return max(SegmentTree::query_max(c,tid[top[x]],tid[x]),query_max(c,fa[top[x]],y));
}
int query_sum(int c,int x,int y){
if(top[x]==top[y]){
if(tid[x]>tid[y])
swap(x,y);
return SegmentTree::query_sum(c,tid[x],tid[y]);
}
if(dep[top[x]]<dep[top[y]])
swap(x,y);
return SegmentTree::query_sum(c,tid[top[x]],tid[x])+query_sum(c,fa[top[x]],y);
}
inline void Replace(int pos,int direction){
int c=rlg[pos];
SegmentTree::Delete(c,tid[pos]);
SegmentTree::Insert(direction,tid[pos],d[pos]);
rlg[pos]=direction;
}
inline void Update(int pos,int v){
d[pos]=v;
SegmentTree::Insert(rlg[pos],tid[pos],v);
}
int main(){
register int i;
int q,u,v;
char buf[5];
scanf("%d%d",&n,&q);
REP_B(i,n){
scanf("%d%d",&d[i],&rlg[i]);
}
REP_B(i,n-1){
scanf("%d%d",&u,&v);
AddEdge(u,v);
AddEdge(v,u);
}
dfs_1(1,0,1);
memset(vis,0,sizeof(vis));
dfs_2(1,1);
while(q--){
memset(buf,0,sizeof(buf));
scanf("%s%d%d",buf,&u,&v);
if(buf[0]=='C'){
if(buf[1]=='W'){
Update(u,v);
}else{
Replace(u,v);
}
}else{
if(buf[1]=='M'){
printf("%d\n",query_max(rlg[u],u,v));
}else{
printf("%d\n",query_sum(rlg[u],u,v));
}
}
}
return 0;
}