bzoj3531 [Sdoi2014]旅行 【樹鏈剖分+線段樹動態開點】

鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531

題意:中文題

分析:由於是在樹上求某一條路徑(u,v)的值,很容易想到用樹鏈剖分求,但是每次求的路徑只需要與(u,v)相同顏色的點的值,不能直接用線段樹統一維護。

我們考慮每種顏色都建一顆線段樹,那麼直接維護相應顏色上的值就行了,但是這樣空間是O(n*n),如果我們建n棵空樹,樹的大小都是0,然後動態將對應顏色的點

插入,由於操作數只有1e5,所以所有線段樹的葉子點加起來不超過O(2*n),線段樹的大小O(8*n) 空間就夠了。

代碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int read() {
    char c;
    int ans=0,f=1;c=getchar();
    while(c<'0'|c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {ans=ans*10+c-'0';c=getchar();}
    return  ans*f;
}
struct edge {
    int v,next;
}e[Mm];
int tot,head[Mn];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int w[Mn],c[Mn];
int siz[Mn],son[Mn],top[Mn],deep[Mn],pre[Mn];
void dfs(int u,int fa,int de) {
    siz[u]=1;deep[u]=de;pre[u]=fa;
    for(int i=head[u];~i;i=e[i].next) {
        if(e[i].v==fa) continue;
        dfs(e[i].v,u,de+1);
        if(son[u]==-1||siz[e[i].v]>siz[son[u]])
            son[u]=e[i].v;
        siz[u]+=siz[e[i].v];
    }
}
int len,inTree[Mn],id[Mn];
void DFS(int u,int tp) {
    top[u]=tp;
    inTree[u]=++len;
    id[inTree[u]]=u;
    if(son[u]==-1) return ;
    else DFS(son[u],tp);
    for(int i=head[u];~i;i=e[i].next)
        if(son[u]!=e[i].v&&e[i].v!=pre[u]) DFS(e[i].v,e[i].v);
}
int root[Mn],ls[Mn*50],rs[Mn*50],cnt;
int sum[Mn*50],maxx[Mn*50];
void pushUp(int node) {
    sum[node]=sum[ls[node]]+sum[rs[node]];
    maxx[node]=max(maxx[ls[node]],maxx[rs[node]]);
}
void update(int &node,int l,int r,int pos,int x) {
    if(!node) node=++cnt;
    if(l==r) {
        maxx[node]=sum[node]=x;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(ls[node],l,mid,pos,x);
    else update(rs[node],mid+1,r,pos,x);
    pushUp(node);
}
int ask(int node,int s,int t,int l,int r,int op) {
    if(!node) return 0;
    if(s<=l&&t>=r) {
        if(op) return maxx[node];
        else return sum[node];
    }
    int r1=0,r2=0;
    int mid=(l+r)>>1;
    if(s<=mid) r1=ask(ls[node],s,t,l,mid,op);
    if(t>mid) r2=ask(rs[node],s,t,mid+1,r,op);
    if(op) return max(r1,r2);
    else return r1+r2;
}
int query(int u,int v,int op) {
    int ans=0,x,C=c[u];
    while(top[u]!=top[v]) {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        x=ask(root[C],inTree[top[u]],inTree[u],1,len,op);
        if(op) ans=max(ans,x);
        else ans+=x;
        u=pre[top[u]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    x=ask(root[C],inTree[u],inTree[v],1,len,op);
    if(op) ans=max(ans,x);
    else ans+=x;
    return ans;
}
void init() {
    tot=0,len=0;cnt=0;
    CLR(head,-1);
    CLR(son,-1);
}
int main() {
    init();
    int 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 u=read(),v=read();
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,0,0);
    DFS(1,1);
    for(int i=1;i<=n;i++)
        update(root[c[id[i]]],1,len,i,w[id[i]]);
    char k[10];
    while(q--) {
        scanf("%s",k);
        int x=read(),y=read();
        if(k[1]=='C') {
            update(root[c[x]],1,len,inTree[x],0);
            update(root[y],1,len,inTree[x],w[x]);
            c[x]=y;
        } else if(k[1]=='S') {
            printf("%d\n",query(x,y,0));
        } else if(k[1]=='W'){
            update(root[c[x]],1,len,inTree[x],y);
            w[x]=y;
        } else if(k[1]=='M') {
            printf("%d\n",query(x,y,1));
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章