P3313 [SDOI2014]旅行

P3313 [SDOI2014]旅行

树链剖分+动态线段树(并不是lct)

显然的,我们对于每一个宗教都要维护一个线段树。

(那么空间不是爆炸了吗)

在这里引入:动态开点线段树

就是需要的点开起来,不需要的就不开。

其他地方和正常的线段树差不多

这样可以省下一堆空间。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#define re register
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
template <typename T> inline void read(T &x){
    char c=getchar(); x=0; bool f=1;
    while(!isdigit(c)) f= !f||c=='-' ? 0:1,c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    x= f ? x:-x;
}
template <typename T> inline void output(T x){
    if(!x) {putchar(48); return ;}
    if(x<0) putchar('-'),x=-x;
    int wt[50],l=0;
    while(x) wt[++l]=x%10,x/=10;
    while(l) putchar(wt[l--]+48);
}
typedef int arr[100003];
struct data{ //结构体存点
    int l,r,mxd,sum;
    void clear() {l=r=mxd=sum=0;} 
}a[2000002]; //尽量开大
queue <int> lit;
int n,m,cnt,tot,u;
arr d,fa,siz,bgs,tp,val,sp,id,hd,ed,rt;
int nxt[200003],poi[200003];
inline void add_(int x,int y){
    nxt[ed[x]]=++cnt; hd[x]= hd[x] ? hd[x]:cnt; 
    ed[x]=cnt; poi[cnt]=y;
}
inline void modify(int &o,int l,int r,int x,int v){ //引用地址便于修改
    if(!o){
        if(!lit.empty()) o=lit.front(),lit.pop(); //内存池节省空间
        else o=++u;
    }
    if(l==r) {a[o].sum=a[o].mxd=v; return;}
    int mid=l+((r-l)>>1);
    if(x<=mid) modify(a[o].l,l,mid,x,v);
    else modify(a[o].r,mid+1,r,x,v);
    a[o].sum=a[a[o].l].sum+a[a[o].r].sum;
    a[o].mxd=max(a[a[o].l].mxd,a[a[o].r].mxd);
}
inline void remov(int &o,int l,int r,int x){
    if(l==r) {a[o].clear(); lit.push(o),o=0; return;}
    int mid=l+((r-l)>>1);
    if(x<=mid) remov(a[o].l,l,mid,x);
    else remov(a[o].r,mid+1,r,x);
    a[o].sum=a[a[o].l].sum+a[a[o].r].sum;
    a[o].mxd=max(a[a[o].l].mxd,a[a[o].r].mxd);
    if(!a[o].l&&!a[o].r) a[o].clear(),lit.push(o),o=0; //左右子树都空->该点为空->删掉
}
inline int query1(int o,int l,int r,int x1,int x2){
    if(!o) return 0; //注意空树要跳出
    if(x1<=l&&r<=x2) return a[o].sum;
    int mid=l+((r-l)>>1),res=0;
    if(x1<=mid) res+=query1(a[o].l,l,mid,x1,x2);
    if(x2>mid) res+=query1(a[o].r,mid+1,r,x1,x2);
    return res;
}
inline int query2(int o,int l,int r,int x1,int x2){
    if(!o) return 0;
    if(x1<=l&&r<=x2) return a[o].mxd;
    int mid=l+((r-l)>>1),res=0;
    if(x1<=mid) res=max(res,query2(a[o].l,l,mid,x1,x2));
    if(x2>mid) res=max(res,query2(a[o].r,mid+1,r,x1,x2));
    return res;
}
inline void dfs1(int x,int _fa){
    d[x]=d[_fa]+1,fa[x]=_fa,siz[x]=1;
    for(int i=hd[x];i;i=nxt[i])
        if(poi[i]!=_fa){
            dfs1(poi[i],x);
            siz[x]+=siz[poi[i]];
            if(siz[bgs[x]]<siz[poi[i]]) bgs[x]=poi[i];
        }
}
inline void dfs2(int x,int _top){
    id[x]=++tot,tp[x]=_top;
    if(siz[x]==1) return;
    dfs2(bgs[x],_top);
    for(int i=hd[x];i;i=nxt[i])
        if(poi[i]!=fa[x]&&poi[i]!=bgs[x])
            dfs2(poi[i],poi[i]);
}
inline int ask1(int x,int y){
    int col=val[x],res=0;
    while(tp[x]!=tp[y]){
        if(d[tp[x]]<d[tp[y]]) swap(x,y);
        res+=query1(rt[col],1,n,id[tp[x]],id[x]);
        x=fa[tp[x]];
    }if(d[x]>d[y]) swap(x,y);
    return res+query1(rt[col],1,n,id[x],id[y]);
}
inline int ask2(int x,int y){
    int col=val[x],res=0;
    while(tp[x]!=tp[y]){
        if(d[tp[x]]<d[tp[y]]) swap(x,y);
        res=max(res,query2(rt[col],1,n,id[tp[x]],id[x]));
        x=fa[tp[x]];
    }if(d[x]>d[y]) swap(x,y);
    return max(res,query2(rt[col],1,n,id[x],id[y]));
}
//------树剖基础操作-------- inline
void change1(int x,int v){ remov(rt[val[x]],1,n,id[x]); modify(rt[val[x]=v],1,n,id[x],sp[x]); }//宗教改变:从原来那棵树删掉该点,再加到新树上 inline void change2(int x,int v){ modify(rt[val[x]],1,n,id[x],sp[x]=v); }//评价改变:直接修改 int main(){ read(n),read(m); int q1,q2; char opt[5]; for(re int i=1;i<=n;++i) read(sp[i]),read(val[i]); for(re int i=1;i<n;++i) read(q1),read(q2),add_(q1,q2),add_(q2,q1); dfs1(1,0); dfs2(1,1); for(re int i=1;i<=n;++i) modify(rt[val[i]],1,n,id[i],sp[i]); for(re int i=1;i<=m;++i){ scanf("%s",opt); read(q1),read(q2); if(opt[0]=='C'){ if(opt[1]=='C') change1(q1,q2); else change2(q1,q2); }else{ if(opt[1]=='S') output(ask1(q1,q2)); else output(ask2(q1,q2)); putchar('\n'); } }return 0; }

 

posted @ 2018-09-28 10:48  kafuuchino  阅读(219)  评论(0编辑  收藏  举报