bzoj3531 [Sdoi2014]旅行 【树链剖分+线段树动态开点】

来源:互联网 发布:九阴真经买淘宝礼包 编辑:程序博客网 时间:2024/05/17 01:58

链接: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)|1using 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;}


0 0
原创粉丝点击