树链剖分

来源:互联网 发布:php视频网站 编辑:程序博客网 时间:2024/06/05 07:04

bzoj3924YES
bzoj4034YES
bzoj1576YES
bzoj3626YES神转化
bzoj2325
bzoj3589
bzoj4538
bzoj2908
bzoj3694YES
bzoj1146二分+树链剖分+线段树套平衡树
bzoj3531YES
bzoj1984YES
bzoj2243YES
bzoj4196YES
bzoj1036YES
poj3237YES

//bzoj3531#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=131072;const int inf=21333333;int dep[N],sz[N],top[N],fa[N],pos[N],h[N];int mx[N*100],sum[N*100],root[N*100],ls[N*100],rs[N*100];int n,m,tot,x,y,z,w[N],c[N],tm,size;struct edge{int y,next;}g[N*2];char s[10];void adp(int x,int y){    g[++tot].y=y;    g[tot].next=h[x];    h[x]=tot;}void dfs1(int x){    sz[x]=1;    for (int i=h[x];i;i=g[i].next)    if (g[i].y!=fa[x]){        fa[g[i].y]=x;        dep[g[i].y]=dep[x]+1;        dfs1(g[i].y);        sz[x]+=sz[g[i].y];    }}void dfs2(int x,int t){    top[x]=t;pos[x]=++tm;    int son=0;    for (int i=h[x];i;i=g[i].next)    if (g[i].y!=fa[x] && sz[son]<sz[g[i].y])        son=g[i].y;    if (son) dfs2(son,t);    for (int i=h[x];i;i=g[i].next)    if (g[i].y!=fa[x] && g[i].y!=son)        dfs2(g[i].y,g[i].y);}int lca(int x,int y){    while (top[x]!=top[y]){        if (dep[top[x]]>dep[top[y]])            x=fa[top[x]]; else            y=fa[top[y]];    }    if (dep[x]<dep[y])        return x;    return y;}void pushup(int rt){    sum[rt]=sum[ls[rt]]+sum[rs[rt]];    mx[rt]=max(mx[ls[rt]],mx[rs[rt]]);}void change(int &rt,int l,int r,int k,int val){    if (!rt) rt=++size;    if (l==r){mx[rt]=sum[rt]=val;return;}    int mid=(l+r)>>1;    if (k<=mid)        change(ls[rt],l,mid,k,val); else        change(rs[rt],mid+1,r,k,val);    pushup(rt);}int querymax(int rt,int l,int r,int ll,int rr){    if (!rt) return 0;    if (l==ll && rr==r) return mx[rt];    int mid=(l+r)>>1;int res=-inf;    if (ll<=mid) res=max(res,querymax(ls[rt],l,mid,ll,min(mid,rr)));    if (rr> mid) res=max(res,querymax(rs[rt],mid+1,r,max(mid+1,ll),rr));    return res;}int querysum(int rt,int l,int r,int ll,int rr){    if (!rt) return 0;    if (l==ll && rr==r) return sum[rt];    int mid=(l+r)>>1;int res=0;    if (ll<=mid) res+=querysum(ls[rt],l,mid,ll,min(mid,rr));    if (rr> mid) res+=querysum(rs[rt],mid+1,r,max(mid+1,ll),rr);    return res;}int querysum(int cc,int x,int f){    int res=0;    while (top[x]!=top[f]){        res+=querysum(root[cc],1,n,pos[top[x]],pos[x]);        x=fa[top[x]];    }    res+=querysum(root[cc],1,n,pos[f],pos[x]);    return res;}int querymax(int cc,int x,int f){    int res=-inf;    while (top[x]!=top[f]){        res=max(res,querymax(root[cc],1,n,pos[top[x]],pos[x]));        x=fa[top[x]];    }    res=max(res,querymax(root[cc],1,n,pos[f],pos[x]));    return res;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)        scanf("%d%d",w+i,c+i);    for (int i=1;i<n;i++){        scanf("%d%d",&x,&y);        adp(x,y);adp(y,x);    }    dfs1(1);dfs2(1,1);    for (int i=1;i<=n;i++)        change(root[c[i]],1,n,pos[i],w[i]);    while (m--){        scanf("%s",s);        if (s[0]=='Q'){            scanf("%d%d",&x,&y);            int f=lca(x,y);            if (s[1]=='S')                printf("%d\n",querysum(c[x],x,f)+querysum(c[x],y,f)-(c[x]==c[f])*w[f]); else                printf("%d\n",max(querymax(c[x],x,f),querymax(c[x],y,f)));        } else {            scanf("%d%d",&x,&z);            if (s[1]=='C'){                change(root[c[x]],1,n,pos[x],0);                c[x]=z;                change(root[c[x]],1,n,pos[x],w[x]);            } else change(root[c[x]],1,n,pos[x],z),w[x]=z;        }    }}

应用

将树上路径转化为序列用线段树维护。
将某棵子树(dfs序)询问转化为序列用线段树维护。
支持单点修改,路径修改,子树修改。
支持路径求和….
注意:树的形态不能变。

0 0
原创粉丝点击