树链剖分

蹲街弑〆低调 提交于 2020-02-17 11:30:27

cogs||bzoj1036 树的统计count

题目大意:模板题。

思路:模板题。

#include<iostream>
#include<cstdio>
#define maxnode 30001
#define mid (l+r)/2
#define inf 2100000000LL
using namespace std;
struct use{
    int fa,top,siz,son,dep,tid;
}tree[maxnode]={0};
struct seg{
    int maxn,sum;
}t[maxnode*4]={0};
int point[maxnode*2]={0},next[maxnode*2]={0},en[maxnode*2],tot=0,tt[maxnode],wi[maxnode];
char ch[10];
bool visit[maxnode]={false};
void add(int st,int enn)
{
    ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;
    ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;
}
void findc(int u,int fa,int depth)
{
    int i,j,maxsiz=0;
    visit[u]=true;tree[u].siz=1;
    tree[u].fa=fa;tree[u].dep=depth;
    for (i=point[u];i;i=next[i])
      if (!visit[en[i]])
      {
        j=en[i];findc(j,u,depth+1);
        tree[u].siz+=tree[j].siz;
        if (tree[j].siz>maxsiz)
        {
            maxsiz=tree[j].siz;
            tree[u].son=j;
        }
      }
}
void connc(int u,int top)
{
    int i,j;
    visit[u]=false;tree[u].top=top;
    tree[u].tid=++tot;tt[tot]=u;
    if (tree[u].son)
        connc(tree[u].son,top);
    for (i=point[u];i;i=next[i])
      if (visit[en[i]])
      {
        j=en[i];connc(j,j);
      }
}
void updata(int i)
{
    t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
    t[i].sum=t[i*2].sum+t[i*2+1].sum;
}
void build(int i,int l,int r)
{
    if (l==r)
    {
        t[i].maxn=t[i].sum=wi[tt[l]];return;
    }
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
void change(int i,int l,int r,int x,int y)
{
    if (l==r)
    {
        t[i].maxn=t[i].sum=y;return;
    }
    if (x<=mid) change(i*2,l,mid,x,y);
    else change(i*2+1,mid+1,r,x,y);
    updata(i);
}
int tmax(int i,int l,int r,int ll,int rr)
{
    int maxn;
    if (ll<=l&&r<=rr) return t[i].maxn;
    maxn=-inf;
    if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr));
    if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr));
    return maxn;
}
int tsum(int i,int l,int r,int ll,int rr)
{
    int sum=0;
    if (ll<=l&&r<=rr) return t[i].sum;
    if (ll<=mid) sum+=tsum(i*2,l,mid,ll,rr);
    if (rr>mid) sum+=tsum(i*2+1,mid+1,r,ll,rr);
    return sum;
}
int qmax(int x,int y)
{
    int maxn;
    maxn=-inf;
    while(tree[x].top!=tree[y].top)
    {
        if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
        maxn=max(maxn,tmax(1,1,tot,tree[tree[x].top].tid,tree[x].tid));
        x=tree[tree[x].top].fa;
    }
    if (tree[x].dep<tree[y].dep) swap(x,y);
    maxn=max(maxn,tmax(1,1,tot,tree[y].tid,tree[x].tid));
    return maxn;
}
int qsum(int x,int y)
{
    int sum=0;
    while(tree[x].top!=tree[y].top)
    {
        if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y);
        sum+=tsum(1,1,tot,tree[tree[x].top].tid,tree[x].tid);
        x=tree[tree[x].top].fa;
    }
    if (tree[x].dep<tree[y].dep) swap(x,y);
    sum+=tsum(1,1,tot,tree[y].tid,tree[x].tid);
    return sum;
}
int main()
{
    freopen("bzoj_1036.in","r",stdin);
    freopen("bzoj_1036.out","w",stdout);
    
    int i,j,n,m,a,b,ans;
    scanf("%d",&n);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    findc(1,0,1);
    tot=0;connc(1,1);
    for (i=1;i<=n;++i) scanf("%d",&wi[i]);
    build(1,1,tot);
    scanf("%d",&m);
    for (i=1;i<=m;++i)
    {
        scanf("%*c%s",&ch);scanf("%d%d",&a,&b);
        if (ch[0]=='C') change(1,1,tot,tree[a].tid,b);
        else
        {
            if (ch[1]=='M') ans=qmax(a,b);
            else ans=qsum(a,b);
            printf("%d\n",ans);
        }
    }
    
    fclose(stdin);
    fclose(stdout);
}
View Code


cogs 树的维护

题目大意:模板题+区间取反。

思路:取反的时候是纯线段树操作,有很多细节:insert、updata和ask的时候都要考虑delta的取值。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxnode 10001
#define mid (l+r)/2
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2],va[maxnode*2],bi[maxnode*2],tt[maxnode]={0},wi[maxnode];
char ch[10];
struct use{
    int maxn,minn,delta,sig;
}t[maxnode*4];
void updata(int i)
{
    t[i].maxn=max((t[i].sig==t[i*2].sig ? t[i*2].maxn : -t[i*2].minn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].maxn : -t[i*2+1].minn));
    t[i].minn=min((t[i].sig==t[i*2].sig ? t[i*2].minn : -t[i*2].maxn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].minn : -t[i*2+1].maxn));
}
void build(int i,int l,int r)
{
    if (l==r)
    {
        t[i].maxn=t[i].minn=wi[tt[l]];
        t[i].delta=t[i].sig=0;return;
    }
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
void paint(int i)
{
    t[i].sig=1-t[i].sig;t[i].delta=1-t[i].delta;
}
void pushdown(int i)
{
    if (t[i].delta)
    {
        paint(i*2);paint(i*2+1);
        t[i].delta=0;
    }
}
void tchange(int i,int l,int r,int x,int y)
{
    if (l==r)
    {
        if (t[i].sig) t[i].maxn=t[i].minn=-y;
        else t[i].maxn=t[i].minn=y;
        return;
    }
    pushdown(i);
    if (x<=mid) tchange(i*2,l,mid,x,y);
    else tchange(i*2+1,mid+1,r,x,y);
    updata(i);
}
void tneg(int i,int l,int r,int ll,int rr)
{
    if (ll<=l&&r<=rr)
    {
        paint(i);return;
    }
    pushdown(i);
    if (ll<=mid) tneg(i*2,l,mid,ll,rr);
    if (rr>mid) tneg(i*2+1,mid+1,r,ll,rr);
    updata(i);
}
int tmax(int i,int l,int r,int ll,int rr)
{
    int maxn;
    if (ll<=l&&r<=rr)
    {
        if (t[i].sig) return -t[i].minn;
        else return t[i].maxn;
    }
    maxn=-inf;pushdown(i);
    if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr));
    if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr));
    return maxn;
}
struct lp{
    int fa[maxnode],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],edge[maxnode],tot;
    bool visit[maxnode];
    void add(int st,int enn,int vaa,int i)
    {
        ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;va[tot]=vaa;bi[tot]=i;
        ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;va[tot]=vaa;bi[tot]=i;
    }
    void dfs1(int u,int ff,int depth,int vaa,int ii)
    {
        int i,j,maxsiz=0;
        visit[u]=true;fa[u]=ff;dep[u]=depth;
        son[u]=0;siz[u]=1;wi[u]=vaa;edge[ii]=u;
        for (i=point[u];i;i=next[i])
          if (!visit[j=en[i]])
          {
              dfs1(j,u,depth+1,va[i],bi[i]);
              siz[u]+=siz[j];
              if (siz[j]>maxsiz)
              {
                  maxsiz=siz[j];son[u]=j;
              }
          }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        visit[u]=false;top[u]=anc;
        tid[u]=++tot;tt[tot]=u;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
          if (visit[j=en[i]]) dfs2(j,j);
    }
    void change(int a,int b)
    {
        a=tid[edge[a]];
        tchange(1,1,tot,a,b);
    }
    void neg(int a,int b)
    {
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            tneg(1,1,tot,tid[top[a]],tid[a]);
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        if (a!=b) tneg(1,1,tot,tid[son[a]],tid[b]);
    }
    void qmax(int a,int b)
    {
        int maxn;
        maxn=-inf;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            maxn=max(maxn,tmax(1,1,tot,tid[top[a]],tid[a]));
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        if (a!=b) maxn=max(maxn,tmax(1,1,tot,tid[son[a]],tid[b]));
        printf("%d\n",maxn);
    }
}tree;
int main()
{
    freopen("maintaintree.in","r",stdin);
    freopen("maintaintree.out","w",stdout);
    
    int n,i,j,a,b,c;
    scanf("%d",&n);tree.tot=0;
    memset(tree.visit,false,sizeof(tree.visit));
    for (i=1;i<n;++i)
    {
        scanf("%d%d%d",&a,&b,&c);
        tree.add(a,b,c,i);
    }
    tree.dfs1(1,0,1,0,0);
    tree.tot=0;tree.dfs2(1,1);
    build(1,1,tree.tot);
    while(scanf("%*c%s",&ch)==1)
    {
        if (ch[0]=='D') break;
        scanf("%d%d",&a,&b);
        if (ch[0]=='C') tree.change(a,b);
        if (ch[0]=='N') tree.neg(a,b);
        if (ch[0]=='Q') tree.qmax(a,b);
    }
    
    fclose(stdin);
    fclose(stdout);
}
View Code

 

bzoj3083 遥远的国度

题目大意:换父亲、改点权、子树最小值。

思路:换父亲是三种情况的分类讨论:我们并不是真的换父亲、重新建树。当前根root,子树的根节点x。1)如果root=x,就查询整棵树;2)如果当lca(root,x)!=x,就查询x的子树;3)如果当lca(root,x)=x,就查询x的儿子中离root最近的那个儿子在整棵树中的补集。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 100001
#define inf 0x7fffffff
using namespace std;
struct use{
    int delta,minn;
}t[maxnode*4]={0};
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},tot=0,id[maxnode]={0};
void updata(int i)
{
    t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void pushdown(int i)
{
    if (t[i].delta)
    {
        t[i*2].minn=t[i*2].delta=t[i].delta;
        t[i*2+1].minn=t[i*2+1].delta=t[i].delta;
        t[i].delta=0;
    }
}
void build(int i,int l,int r)
{
    int mid;
    if (l==r)
    {
        t[i].delta=0;t[i].minn=fy[id[l]];return;
    }
    mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
void tch(int i,int l,int r,int ll,int rr,int v)
{
    int mid;
    if (ll<=l&&r<=rr)
    {
        t[i].delta=t[i].minn=v;return;
    }
    mid=(l+r)/2;
    pushdown(i);
    if (ll<=mid) tch(i*2,l,mid,ll,rr,v);
    if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v);
    updata(i);
}
int task(int i,int l,int r,int ll,int rr)
{
    int mid,ans;
    if (ll<=l&&r<=rr) return t[i].minn;
    mid=(l+r)/2;ans=inf;pushdown(i);
    if (ll<=mid) ans=min(ans,task(i*2,l,mid,ll,rr));
    if (rr>mid) ans=min(ans,task(i*2+1,mid+1,r,ll,rr));
    return ans;
}
struct lp{
    int fa[maxnode][20],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],ri[maxnode];
    bool visit[maxnode];
    void add(int st,int enn)
    {
        ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;
        ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;
    }
    void dfs1(int u,int ff,int depth)
    {
        int i,j,maxsiz=0;
        visit[u]=true;fa[u][0]=ff;dep[u]=depth;
        son[u]=0;siz[u]=1;
        for (i=1;i<=18;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
        for (i=point[u];i;i=next[i])
        {
            if (!visit[j=en[i]])
            {
                dfs1(j,u,depth+1);
                siz[u]+=siz[j];
                if (siz[j]>maxsiz)
                {
                    maxsiz=siz[j];son[u]=j;
                }
            }
        }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        visit[u]=false;top[u]=anc;
        tid[u]=++tot;id[tot]=u;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
        {
            if (visit[j=en[i]]) dfs2(j,j);
        }
        ri[u]=tot;
    }
    int lca(int a,int b)
    {
        int i,j;
        if (dep[a]>dep[b]) swap(a,b);
        for (i=18;i>=0;--i)
            if (dep[a]<=dep[fa[b][i]]) b=fa[b][i];
        if (a==b) return a;
        for (i=18;i>=0;--i)
        {
            if (fa[a][i]!=fa[b][i])
            {
                a=fa[a][i];b=fa[b][i];
            }
        }
        return fa[a][0];
    }
    void change(int a,int b,int v)
    {
        int i,j;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            tch(1,1,tot,tid[top[a]],tid[a],v);
            a=fa[top[a]][0];
        }
        if (dep[a]>dep[b]) swap(a,b);
        tch(1,1,tot,tid[a],tid[b],v);
    }
    int ask(int a,int root)
    {
        int ans,ll,i,j;
        if (a==root) return task(1,1,tot,1,tot);
        ll=lca(a,root);
        if (ll!=a) return task(1,1,tot,tid[a],ri[a]);
        else
        {
            ans=inf;j=root;
            for (i=18;i>=0;--i)
                if (dep[fa[j][i]]>dep[a]) j=fa[j][i];
            ans=min((tid[j]>1 ? task(1,1,tot,1,tid[j]-1) : inf),(ri[j]<tot ? task(1,1,tot,ri[j]+1,tot) : inf));
            return ans;
        }
    }
}tree;
int main()
{
    int u,v,n,m,i,j,opt,root,p1,p2,ans;
    scanf("%d%d",&n,&m);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        tree.add(u,v);
    }
    for (i=1;i<=n;++i) scanf("%d",&fy[i]);
    scanf("%d",&root);tot=0;
    memset(tree.visit,false,sizeof(tree.visit));
    tree.dfs1(root,0,1);
    tree.dfs2(root,root);
    build(1,1,tot);
    for (i=1;i<=m;++i)
    {
        scanf("%d",&opt);
        if (opt==1) scanf("%d",&root);
        if (opt==2)
        {
            scanf("%d%d%d",&p1,&p2,&v);
            tree.change(p1,p2,v);
        }
        if (opt==3)
        {
            scanf("%d",&p1);
            ans=tree.ask(p1,root);
            printf("%d\n",ans);
        }
    }
}
View Code

 

bzoj2243 染色

题目大意:区间修改、区间不同子段的个数。

思路:线段树上的操作。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 100001
using namespace std;
struct use{
    int lc,rc,sum,delta;
}t[maxnode*4]={0};
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},id[maxnode]={0},tot=0,fy[maxnode]={0};
void updata(int i)
{
    t[i].lc=t[i*2].lc;t[i].rc=t[i*2+1].rc;
    t[i].sum=t[i*2].sum+t[i*2+1].sum;
    if (t[i*2].rc==t[i*2+1].lc) --t[i].sum;
}
void pushdown(int i)
{
    if (t[i].delta>=0)
    {
        t[i*2].lc=t[i*2].rc=t[i*2].delta=t[i].delta;t[i*2].sum=1;
        t[i*2+1].lc=t[i*2+1].rc=t[i*2+1].delta=t[i].delta;t[i*2+1].sum=1;
        t[i].delta=-1;
    }
}
void build(int i,int l,int r)
{
    int mid;
    if (l==r)
    {
        t[i].lc=t[i].rc=fy[id[l]];t[i].sum=1;t[i].delta=-1;return;
    }
    mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);t[i].delta=-1;
}
void tch(int i,int l,int r,int ll,int rr,int v)
{
    int mid;
    if (ll<=l&&r<=rr)
    {
        t[i].lc=t[i].rc=t[i].delta=v;t[i].sum=1;return;
    }
    mid=(l+r)/2;pushdown(i);
    if (ll<=mid) tch(i*2,l,mid,ll,rr,v);
    if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v);
    updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
    int mid,sum=0;
    bool u1=false,u2=false;
    struct use n1,n2,ans;
    if (ll<=l&&r<=rr) return t[i];
    mid=(l+r)/2;pushdown(i);
    if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
    if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
    if (u1) ans.lc=n1.lc;
    else ans.lc=n2.lc;
    if (u2) ans.rc=n2.rc;
    else ans.rc=n1.rc;
    ans.sum=(u1 ? n1.sum : 0)+(u2 ? n2.sum : 0);
    if (u1&&u2&&n1.rc==n2.lc) --ans.sum;
    return ans;
}
struct lp{
    int fa[maxnode],dep[maxnode],son[maxnode],siz[maxnode],top[maxnode],tid[maxnode];
    bool visit[maxnode];
    void add(int u,int v)
    {
        ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
        ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
    }
    void dfs1(int u,int ff,int depth)
    {
        int i,j,maxsiz=0;
        fa[u]=ff;dep[u]=depth;son[u]=0;
        visit[u]=true;siz[u]=1;
        for (i=point[u];i;i=next[i])
        {
            if (!visit[j=en[i]])
            {
                dfs1(j,u,depth+1);
                siz[u]+=siz[j];
                if (siz[j]>maxsiz)
                {
                    maxsiz=siz[j];son[u]=j;
                }
            }
        }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        tid[u]=++tot;top[u]=anc;
        visit[u]=false;id[tot]=u;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
        {
            if (visit[j=en[i]]) dfs2(j,j);
        }
    }
    void change(int a,int b,int v)
    {
        int i;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            tch(1,1,tot,tid[top[a]],tid[a],v);
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        tch(1,1,tot,tid[a],tid[b],v);
    }
    int ask(int a,int b)
    {
        int ans=0,co[2],kk=0;
        struct use i;
        co[0]=co[1]=-1;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]])
            {
                swap(a,b);kk^=1;
            }
            i=task(1,1,tot,tid[top[a]],tid[a]);
            ans+=i.sum;
            if (co[kk]==i.rc) --ans;
            co[kk]=i.lc;
            a=fa[top[a]];
        }
        if (dep[a]>dep[b])
        {
            swap(a,b);kk^=1;
        }
        i=task(1,1,tot,tid[a],tid[b]);
        ans+=i.sum;
        if (co[kk]==i.lc) --ans;
        co[kk]=i.rc;
        if (co[kk]==co[kk^1]) --ans;
        return ans;
    }
}tree;
int main()
{
    int n,m,i,j,u,v,t;
    char ch;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i) scanf("%d",&fy[i]);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);tree.add(u,v);
    }
    memset(tree.visit,false,sizeof(tree.visit));
    tree.dfs1(1,0,1);tot=0;
    tree.dfs2(1,1);build(1,1,tot);
    for (i=1;i<=m;++i)
    {
        while(scanf("%c",&ch)==1)
        {
            if (ch=='C'||ch=='Q') break;
        }
        if (ch=='C')
        {
            scanf("%d%d%d",&u,&v,&t);
            tree.change(u,v,t);
        }
        else
        {
            scanf("%d%d",&u,&v);
            printf("%d\n",tree.ask(u,v));
        }
    }
}
View Code

 

codevs3305&&3306 水果姐逛水果街系列

题目大意:查询树上从a到b的路径中后面减前面的最大差值(+单点修改)。

思路:链剖+线段树的操作,稍复杂一点,分类讨论。有点像上一题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 200001
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0;
struct use{
    int maxn,minn,mac,mic;
}t[maxnode*4];
void updata(int i)
{
    t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn));
    t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn));
    t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
    t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void build(int i,int l,int r)
{
    int mid;
    if (l==r)
    {
        t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return;
    }
    mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
void tch(int i,int l,int r,int x,int y)
{
    int mid;
    if (l==r)
    {
        t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return;
    }
    mid=(l+r)/2;
    if (x<=mid) tch(i*2,l,mid,x,y);
    else tch(i*2+1,mid+1,r,x,y);
    updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
    int mid;
    struct use n1,n2,ans;
    bool u1=false,u2=false;
    if (ll<=l&&r<=rr) return t[i];
    mid=(l+r)/2;
    if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
    if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
    ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0;
    if (u1)
    {
        ans.maxn=max(ans.maxn,n1.maxn);
        ans.minn=min(ans.minn,n1.minn);
        ans.mac=max(ans.mac,n1.mac);
        ans.mic=max(ans.mic,n1.mic);
    }
    if (u2)
    {
        ans.maxn=max(ans.maxn,n2.maxn);
        ans.minn=min(ans.minn,n2.minn);
        ans.mac=max(ans.mac,n2.mac);
        ans.mic=max(ans.mic,n2.mic);
    }
    if (u1&&u2)
    {
        ans.mac=max(ans.mac,n2.maxn-n1.minn);
        ans.mic=max(ans.mic,n1.maxn-n2.minn);
    }
    return ans;
}
struct lp{
    int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode];
    bool visit[maxnode];
    void add(int u,int v)
    {
        ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
        ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
    }
    void dfs1(int u,int ff,int depth)
    {
        int i,j,maxsiz=0;
        fa[u]=ff;dep[u]=depth;visit[u]=true;
        son[u]=0;siz[u]=1;
        for (i=point[u];i;i=next[i])
        {
            if (!visit[j=en[i]])
            {
                dfs1(j,u,depth+1);
                siz[u]+=siz[j];
                if (siz[j]>maxsiz)
                {
                    maxsiz=siz[j];son[u]=j;
                }
            }
        }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        top[u]=anc;tid[u]=++tot;
        id[tot]=u;visit[u]=false;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
            if (visit[j=en[i]]) dfs2(j,j);
    }
    int ask(int a,int b)
    {
        int j,ans=0,kk=0;
        struct use mo[2],i;
        mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf;
        mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]])
            {
                swap(a,b);kk^=1;
            }
            i=task(1,1,tot,tid[top[a]],tid[a]);
            if (!kk)
            {
                ans=max(ans,max(i.mic,i.maxn-mo[kk].minn));
                mo[kk].minn=min(mo[kk].minn,i.minn);
                mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            }
            else
            {
                ans=max(ans,max(i.mac,mo[kk].maxn-i.minn));
                mo[kk].minn=min(mo[kk].minn,i.minn);
                mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            }
            a=fa[top[a]];
        }
        if (dep[a]>dep[b])
        {
            swap(a,b);kk^=1;
        }
        i=task(1,1,tot,tid[a],tid[b]);
        if (!kk)
        {
            ans=max(ans,max(i.mac,i.maxn-mo[kk].minn));
            mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            mo[kk].minn=min(mo[kk].minn,i.minn);
            ans=max(ans,mo[kk^1].maxn-mo[kk].minn);
        }
        else
        {
            ans=max(ans,max(i.mic,mo[kk].maxn-i.minn));
            mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            mo[kk].minn=min(mo[kk].minn,i.minn);
            ans=max(ans,mo[kk].maxn-mo[kk^1].minn);
        }
        return ans;
    }
}tree;
int main()
{
    int n,m,i,j,x,y,u,v;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%d",&fy[i]);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        tree.add(u,v);
    }
    memset(tree.visit,false,sizeof(tree.visit));
    tree.dfs1(1,0,1);tot=0;
    tree.dfs2(1,1);scanf("%d",&m);
    build(1,1,tot);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",tree.ask(x,y));
    }
}
无修改
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxnode 200001
#define inf 2100000000
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0;
struct use{
    int maxn,minn,mac,mic;
}t[maxnode*4];
void updata(int i)
{
    t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn));
    t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn));
    t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn);
    t[i].minn=min(t[i*2].minn,t[i*2+1].minn);
}
void build(int i,int l,int r)
{
    int mid;
    if (l==r)
    {
        t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return;
    }
    mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
void tch(int i,int l,int r,int x,int y)
{
    int mid;
    if (l==r)
    {
        t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return;
    }
    mid=(l+r)/2;
    if (x<=mid) tch(i*2,l,mid,x,y);
    else tch(i*2+1,mid+1,r,x,y);
    updata(i);
}
struct use task(int i,int l,int r,int ll,int rr)
{
    int mid;
    struct use n1,n2,ans;
    bool u1=false,u2=false;
    if (ll<=l&&r<=rr) return t[i];
    mid=(l+r)/2;
    if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);}
    if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);}
    ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0;
    if (u1)
    {
        ans.maxn=max(ans.maxn,n1.maxn);
        ans.minn=min(ans.minn,n1.minn);
        ans.mac=max(ans.mac,n1.mac);
        ans.mic=max(ans.mic,n1.mic);
    }
    if (u2)
    {
        ans.maxn=max(ans.maxn,n2.maxn);
        ans.minn=min(ans.minn,n2.minn);
        ans.mac=max(ans.mac,n2.mac);
        ans.mic=max(ans.mic,n2.mic);
    }
    if (u1&&u2)
    {
        ans.mac=max(ans.mac,n2.maxn-n1.minn);
        ans.mic=max(ans.mic,n1.maxn-n2.minn);
    }
    return ans;
}
struct lp{
    int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode];
    bool visit[maxnode];
    void add(int u,int v)
    {
        ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
        ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
    }
    void dfs1(int u,int ff,int depth)
    {
        int i,j,maxsiz=0;
        fa[u]=ff;dep[u]=depth;visit[u]=true;
        son[u]=0;siz[u]=1;
        for (i=point[u];i;i=next[i])
        {
            if (!visit[j=en[i]])
            {
                dfs1(j,u,depth+1);
                siz[u]+=siz[j];
                if (siz[j]>maxsiz)
                {
                    maxsiz=siz[j];son[u]=j;
                }
            }
        }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        top[u]=anc;tid[u]=++tot;
        id[tot]=u;visit[u]=false;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
            if (visit[j=en[i]]) dfs2(j,j);
    }
    int ask(int a,int b)
    {
        int j,ans=0,kk=0;
        struct use mo[2],i;
        mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf;
        mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]])
            {
                swap(a,b);kk^=1;
            }
            i=task(1,1,tot,tid[top[a]],tid[a]);
            if (!kk)
            {
                ans=max(ans,max(i.mic,i.maxn-mo[kk].minn));
                mo[kk].minn=min(mo[kk].minn,i.minn);
                mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            }
            else
            {
                ans=max(ans,max(i.mac,mo[kk].maxn-i.minn));
                mo[kk].minn=min(mo[kk].minn,i.minn);
                mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            }
            a=fa[top[a]];
        }
        if (dep[a]>dep[b])
        {
            swap(a,b);kk^=1;
        }
        i=task(1,1,tot,tid[a],tid[b]);
        if (!kk)
        {
            ans=max(ans,max(i.mac,i.maxn-mo[kk].minn));
            mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            mo[kk].minn=min(mo[kk].minn,i.minn);
            ans=max(ans,mo[kk^1].maxn-mo[kk].minn);
        }
        else
        {
            ans=max(ans,max(i.mic,mo[kk].maxn-i.minn));
            mo[kk].maxn=max(mo[kk].maxn,i.maxn);
            mo[kk].minn=min(mo[kk].minn,i.minn);
            ans=max(ans,mo[kk].maxn-mo[kk^1].minn);
        }
        return ans;
    }
}tree;
int main()
{
    int n,m,i,j,x,y,u,v;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%d",&fy[i]);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        tree.add(u,v);
    }
    memset(tree.visit,false,sizeof(tree.visit));
    tree.dfs1(1,0,1);tot=0;
    tree.dfs2(1,1);scanf("%d",&m);
    build(1,1,tot);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d%d",&j,&x,&y);
        if (j==0) tch(1,1,tot,tree.tid[x],y);
        else printf("%d\n",tree.ask(x,y));
    }
}
有修改

 

moe

题目大意:给定一个图,有两种操作:1)删掉一条边;2)求图中桥的数量。

思路:对于删边类的问题,大多是倒着来做。删掉所有边后,可能仍然是个图,我们dfs出一棵树,这些边都是当前的桥,把图中的边一条一条加上,它连接的两点间的边都不是桥了,维护的过程就是链剖+线段树区间修改和查询。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxnode 100005
using namespace std;
struct use{
    int st,en,flag;
}edge[maxnode]={0};
struct uu{
    int num,delta;
}t[maxnode*4]={0};
int tot=0,ask[maxnode][4]={0},point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},n,tot1=0;
bool visit[maxnode]={false};
map <int,int> dui[maxnode];
void add(int u,int v)
{
    edge[++tot].st=u;edge[tot].en=v;edge[tot].flag=0;
    dui[u][v]=dui[v][u]=tot;
    next[tot*2-1]=point[u];point[u]=tot*2-1;en[tot*2-1]=v;
    next[tot*2]=point[v];point[v]=tot*2;en[tot*2]=u;
}
void updata(int i){t[i].num=t[i*2].num+t[i*2+1].num;}
void pushdown(int i,int l,int r)
{
    int mid;
    if (t[i].delta)
    {
        t[i*2].delta=t[i*2+1].delta=1;
        t[i*2].num=t[i*2+1].num=0;
        t[i].delta=0;
    }
}
void build(int i,int l,int r)
{
    int mid;
    if (l==r){t[i].num=1;t[i].delta=0;return;}
    mid=(l+r)/2;build(i*2,l,mid);build(i*2+1,mid+1,r);
    updata(i);
}
int task(int i,int l,int r,int ll,int rr)
{
    int mid,ans=0;
    if (ll<=l&&r<=rr) return t[i].num;
    mid=(l+r)/2;pushdown(i,l,r);
    if (ll<=mid) ans+=task(i*2,l,mid,ll,rr);
    if (rr>mid) ans+=task(i*2+1,mid+1,r,ll,rr);
    return ans;
}
void tch(int i,int l,int r,int ll,int rr)
{
    int mid;
    if (ll<=l&&r<=rr)
    {
        t[i].num=0;t[i].delta=1;return;
    } mid=(l+r)/2;pushdown(i,l,r);
    if (ll<=mid) tch(i*2,l,mid,ll,rr);
    if (rr>mid) tch(i*2+1,mid+1,r,ll,rr);
    updata(i);
}
struct lp{
    int fa[maxnode],tid[maxnode],son[maxnode],siz[maxnode],top[maxnode],dep[maxnode];
    void dfs1(int u,int faa,int depth)
    {
        int maxsiz=0,i,j;
        fa[u]=faa;dep[u]=depth;
        son[u]=0;siz[u]=1;visit[u]=true;
        for (i=point[u];i;i=next[i])
            if (edge[(i+1)/2].flag==0&&!visit[en[i]])
            {
                edge[(i+1)/2].flag=1;
                dfs1(en[i],u,depth+1);siz[u]+=siz[en[i]];
                if (siz[en[i]]>maxsiz)
                {
                    son[u]=en[i];maxsiz=siz[en[i]];
                }
            }
    }
    void dfs2(int u,int anc)
    {
        int i,j;
        tid[u]=++tot1;top[u]=anc;visit[u]=false;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
            if (edge[(i+1)/2].flag==1&&visit[en[i]])
              dfs2(en[i],en[i]);
    }
    void change(int a,int b)
    {
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            tch(1,1,n,tid[top[a]],tid[a]);
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        if (a!=b) tch(1,1,n,tid[son[a]],tid[b]);
    }
    int query(int a,int b)
    {
        int ans=0;
        while(top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ans+=task(1,1,n,tid[top[a]],tid[a]);
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        if (a!=b) ans+=task(1,1,n,tid[son[a]],tid[b]);
        return ans;
    }
}tree;
int main()
{
    freopen("moe.in","r",stdin);
    freopen("moe.out","w",stdout);
    
    int m,i,j,c,a,b,tt=0;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;++i){scanf("%d%d",&a,&b);add(a,b);}
    while(scanf("%d",&c)==1)
    {
        if (c==-1) break;
        scanf("%d%d",&a,&b);
        ask[++tt][0]=c;ask[tt][1]=a;ask[tt][2]=b;
        if (!c) edge[dui[a][b]].flag=-1;
    }
    tree.dfs1(1,0,1);tree.dfs2(1,1);build(1,1,n);
    for (i=1;i<=tot;++i)
        if (edge[i].flag==0) tree.change(edge[i].st,edge[i].en);
    for (i=tt;i>=1;--i)
    {
        if (ask[i][0]==0) tree.change(ask[i][1],ask[i][2]);
        else ask[i][3]=tree.query(ask[i][1],ask[i][2]);
    }
    for (i=1;i<=tt;++i)
      if (ask[i][0]) printf("%d\n",ask[i][3]);
      
    fclose(stdin);
    fclose(stdout);
}
View Code

 

sdoi2014 旅行

题目大意:给定一棵树和树上节点的颜色和权值,求两点路径上的某种颜色的权值和和权值最大值。

思路:树链剖分+动态开点线段树。对每种颜色建线段树,然后更新就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 100005
#define inf 2100000000
using namespace std;
struct use{
    int ls,rs,l,r,maxn,sum;
}t[maxm*100]={0};
int wi[maxm]={0},ci[maxm]={0},point[maxm]={0},en[maxm*2]={0},next[maxm*2]={0},tot=0,n,sum=0,
    id[maxm]={0},root[maxm]={0};
char ss[10];
void add(int u,int v){
    next[++tot]=point[u];point[u]=tot;en[tot]=v;
    next[++tot]=point[v];point[v]=tot;en[tot]=u;
}
void updata(int i){
    t[i].maxn=max(t[t[i].ls].maxn,t[t[i].rs].maxn);
    t[i].sum=t[t[i].ls].sum+t[t[i].rs].sum;
}
void tins(int &i,int l,int r,int x,int w,int kk){
    if (!i){t[i=++sum].l=l;t[i].r=r;t[i].maxn=-inf;}
    if (l==r){
        if (kk>0) t[i].maxn=t[i].sum=w;
        else{t[i].maxn=-inf;t[i].sum=0;}
        return;
    }int mid=(l+r)/2;
    if (x<=mid) tins(t[i].ls,l,mid,x,w,kk);
    else tins(t[i].rs,mid+1,r,x,w,kk);
    updata(i);
}
int tsum(int i,int l,int r,int ll,int rr){
    int mid,ans=0;if (!i) return 0;
    if (ll<=l&&r<=rr) return t[i].sum;
    mid=(l+r)/2;
    if (ll<=mid) ans+=tsum(t[i].ls,l,mid,ll,rr);
    if (rr>mid) ans+=tsum(t[i].rs,mid+1,r,ll,rr);
    return ans;
}
int tmax(int i,int l,int r,int ll,int rr){
    int mid,ans;ans=-inf;
    if (!i) return -inf;
    if (ll<=l&&r<=rr) return t[i].maxn;
    mid=(l+r)/2;
    if (ll<=mid) ans=max(ans,tmax(t[i].ls,l,mid,ll,rr));
    if (rr>mid) ans=max(ans,tmax(t[i].rs,mid+1,r,ll,rr));
    return ans;
}
struct lp{
    int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm];
    bool visit[maxm];
    void dfs1(int u,int faa,int de){
        int i,j,maxsiz=0;fa[u]=faa;dep[u]=de;
        son[u]=0;siz[u]=1;visit[u]=false;
        for (i=point[u];i;i=next[i])
            if ((j=en[i])!=faa){
                dfs1(j,u,de+1);siz[u]+=siz[j];
                if (siz[j]>maxsiz){maxsiz=siz[j];son[u]=j;}
            }
    }
    void dfs2(int u,int anc){
        int i,j;top[u]=anc;visit[u]=true;
        tid[u]=++tot;id[tot]=u;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i])
            if (!visit[j=en[i]]) dfs2(j,j);
    }
    int qsum(int a,int b){
        int ans=0,co;co=ci[a];
        while(top[a]!=top[b]){
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ans+=tsum(root[co],1,n,tid[top[a]],tid[a]);
            a=fa[top[a]];
        }if (dep[a]>dep[b]) swap(a,b);
        ans+=tsum(root[co],1,n,tid[a],tid[b]);
        return ans;
    }
    int qmax(int a,int b){
        int ans=-inf;int co=ci[a];
        while(top[a]!=top[b]){
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ans=max(ans,tmax(root[co],1,n,tid[top[a]],tid[a]));
            a=fa[top[a]];
        }if (dep[a]>dep[b]) swap(a,b);
        ans=max(ans,tmax(root[co],1,n,tid[a],tid[b]));
        return ans;
    }
}tree;
int main()
{
    int q,i,j,u,v;scanf("%d%d",&n,&q);
    for (i=1;i<=n;++i) scanf("%d%d",&wi[i],&ci[i]);
    for (i=1;i<n;++i){scanf("%d%d",&u,&v);add(u,v);}
    tree.dfs1(1,0,1);tot=0;tree.dfs2(1,1);
    t[0].maxn=-inf;t[0].sum=0;
    for (i=1;i<=n;++i)
        tins(root[ci[i]],1,n,tree.tid[i],wi[i],1);
    for (i=1;i<=q;++i){
        scanf("%s",&ss);scanf("%d%d",&u,&v);
        if (ss[0]=='C'){
            if (ss[1]=='C'){
              tins(root[ci[u]],1,n,tree.tid[u],wi[u],-1);
              tins(root[ci[u]=v],1,n,tree.tid[u],wi[u],1);
            }
            else tins(root[ci[u]],1,n,tree.tid[u],wi[u]=v,1);
        }else{
            if (ss[1]=='S') printf("%d\n",tree.qsum(u,v));
            else printf("%d\n",tree.qmax(u,v));
        }
    }
}
View Code

 

bzoj4336 骑士的旅行

题目大意:给定一棵树,有m个骑士在这棵树上,查询一条链上前k个骑士的武力值,修改:1)一个骑士换一个点;2)骑士换一个武力值。

思路:树链剖分+线段树+map。因为k很小,所以可以在线段树里维护出前k大的。用map记录一下每个点上的骑士的信息,用线段树维护,树链剖分查询就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxm 40005
#define maxx 80005
using namespace std;
map<int,int> cnt[maxm];
int n,k,point[maxm]={0},en[maxx]={0},next[maxx]={0},tot=0,ti=0,id[maxm]={0};
bool visit[maxm]={false};
struct use{
    int ki[21];
    void init(){ki[0]=0;}
}t[maxm*4];
inline int sc(){
    char ch=getchar();int x=0;
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';ch=getchar();
    }return x;
}
struct uu{int po,v;}qi[maxm];
inline void add(int u,int v){
    next[++tot]=point[u];point[u]=tot;en[tot]=v;
    next[++tot]=point[v];point[v]=tot;en[tot]=u;
}
inline void in(int i,int x){
    int tt;t[i].init();
    if (!cnt[x].size()) return;
    map<int,int>::iterator it;
    for (it=cnt[x].end(),--it;;--it){
        for (tt=min(it->second,k-t[i].ki[0]);tt;--tt)
            t[i].ki[++t[i].ki[0]]=it->first;
        if (t[i].ki[0]==k||it==cnt[x].begin()) break;
    }
}
inline use updata(use x,use y){
    use cc;cc.init();
    int i=1,j=1;
    while(i<=x.ki[0]&&j<=y.ki[0]&&cc.ki[0]<k){
        if (x.ki[i]>=y.ki[j])
          cc.ki[++cc.ki[0]]=x.ki[i++];
        else cc.ki[++cc.ki[0]]=y.ki[j++];
    }if (cc.ki[0]<k){
        if (i<=x.ki[0])
          for (;i<=x.ki[0]&&cc.ki[0]<k;++i)
              cc.ki[++cc.ki[0]]=x.ki[i];
        else
          for (;j<=y.ki[0]&&cc.ki[0]<k;++j)
            cc.ki[++cc.ki[0]]=y.ki[j];
    }return cc;
}
inline void build(int i,int l,int r){
    if (l==r){in(i,id[l]);return;}
    int mid=(l+r)>>1;
    build(i<<1,l,mid);build(i<<1|1,mid+1,r);
    t[i]=updata(t[i<<1],t[i<<1|1]);
}
inline void tch(int i,int l,int r,int x){
    if (l==r){in(i,id[l]);return;}
    int mid=(l+r)>>1;
    if (x<=mid) tch(i<<1,l,mid,x);
    else tch(i<<1|1,mid+1,r,x);
    t[i]=updata(t[i<<1],t[i<<1|1]);
}
inline use task(int i,int l,int r,int ll,int rr){
    use cc;cc.init();
    if (ll<=l&&r<=rr) return t[i];
    int mid=(l+r)>>1;
    if (ll<=mid) cc=updata(cc,task(i<<1,l,mid,ll,rr));
    if (rr>mid) cc=updata(cc,task(i<<1|1,mid+1,r,ll,rr));
    return cc;
}
struct lp{
    int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm];
    inline void dfs1(int u,int ff,int de){
        int i,v,maxsiz=0;dep[u]=de;
        siz[u]=1;son[u]=0;fa[u]=ff;
        for (i=point[u];i;i=next[i]){
            if ((v=en[i])==ff) continue;
            dfs1(v,u,de+1);siz[u]+=siz[v];
            if (siz[v]>maxsiz){maxsiz=siz[v];son[u]=v;}
        }
    }
    inline void dfs2(int u,int anc){
        int i,v;top[u]=anc;visit[u]=true;
        tid[u]=++ti;id[ti]=u;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i]){
            if (visit[v=en[i]]) continue;
            dfs2(v,v);
        }
    }
    inline use ask(int x,int y){
        use cc;cc.init();
        while(top[x]!=top[y]){
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            cc=updata(cc,task(1,1,n,tid[top[x]],tid[x]));
            x=fa[top[x]];
        }if (dep[x]>dep[y]) swap(x,y);
        cc=updata(cc,task(1,1,n,tid[x],tid[y]));
        return cc;
    }
}tree;
int main(){
    int m,i,j,u,v,q,ti,xi,yi;
    use ci;n=sc();
    for (i=1;i<n;++i){u=sc();v=sc();add(u,v);}
    tree.dfs1(1,0,1);tree.dfs2(1,1);m=sc();
    for (i=1;i<=m;++i){
        qi[i].v=sc();qi[i].po=sc();
        ++cnt[qi[i].po][qi[i].v];
    }q=sc();k=sc();build(1,1,n);
    for (i=1;i<=q;++i){
        ti=sc();xi=sc();yi=sc();
        if (ti==1){
            ci=tree.ask(xi,yi);
            if (!ci.ki[0]) printf("-1\n");
            else{
              for (j=1;j<=ci.ki[0];++j) printf("%d ",ci.ki[j]);
              printf("\n");
            }
        }if (ti==2){
            --cnt[qi[xi].po][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]);
            ++cnt[qi[xi].po=yi][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]);
        }if (ti==3){
            --cnt[qi[xi].po][qi[xi].v];
            ++cnt[qi[xi].po][qi[xi].v=yi];
            tch(1,1,n,tree.tid[qi[xi].po]);
        }
    }
}
View Code

 

bzoj3626 LCA

题目大意:给定一棵树,每个询问是求sigma(i=l~r)dep(lca(i,z))。

思路:容斥+树链剖分。答案显然是1~l-1的和-1~r的和,所以要求1~i与z的lca的深度和。离线操作,把所有的l、r排序,把1~n依次加入树中,所以就是求树中有的点和z的lca的dep和,因为lca的dep和就是z到根的路径上,每个点的不在这条链上的孩子的个数乘这个点的dep,这个可以用链剖来求,建两棵线段树:一棵维护树上那些点标记,一棵维护这一段区间对应点的答案(这个答案是这个点的子树中不再这个点所在重链的点的个数*dep),查询的时候要在轻重链的地方式子算一下,插入的时候插给这个点到1的路径上所有轻重链交替的点就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 50005
#define maxe 100005
#define p 201314
#define LL long long
using namespace std;
struct use{
    int x,z,po;
    bool operator<(const use&xx)const{
        return x==xx.x ? z<xx.z : x<xx.x;
    }
}li[maxm],ri[maxm],lr[maxe];
int point[maxm]={0},next[maxm]={0},en[maxm]={0},tot=0,id[maxm],ti=0,n,la[maxm]={0},
    tree[maxm*4]={0},fa[maxm],tid[maxm],top[maxm],son[maxm];
LL t[maxm*4]={0LL},sizb[maxm]={0LL},siz[maxm],dep[maxm],ans[maxm]={0LL};
bool visit[maxm]={false};
void add(int u,int v){next[++tot]=point[u];point[u]=tot;en[tot]=v;}
LL task(int i,int l,int r,int ll,int rr){
    if (ll<=l&&r<=rr) return t[i];
    int mid=l+r>>1;LL ans=0LL;
    if (ll<=mid) ans+=task(i<<1,l,mid,ll,rr);
    if (rr>mid) ans+=task(i<<1|1,mid+1,r,ll,rr);
    return ans;
}
void tch(int i,int l,int r,int x){
    if (l==r){t[i]=dep[id[l]]*sizb[id[l]]%p;return;}
    int mid=l+r>>1;
    if (x<=mid) tch(i<<1,l,mid,x);
    else tch(i<<1|1,mid+1,r,x);
    t[i]=(t[i<<1]+t[i<<1|1])%p;
}
void change(int i,int l,int r,int x){
    if (l==r){tree[i]=1;return;}
    int mid=l+r>>1;
    if (x<=mid) change(i<<1,l,mid,x);
    else change(i<<1|1,mid+1,r,x);
    tree[i]=tree[i<<1]+tree[i<<1|1];
}
int asum(int i,int l,int r,int ll,int rr){
    if (ll<=l&&r<=rr) return tree[i];
    int mid=l+r>>1;int sum=0;
    if (ll<=mid) sum+=asum(i<<1,l,mid,ll,rr);
    if (rr>mid) sum+=asum(i<<1|1,mid+1,r,ll,rr);
    return sum;
}
struct lp{
    void dfs1(int u,int ff,int de){
        int i,j,v;LL mas=0;
        dep[u]=de;fa[u]=ff;
        son[u]=0;siz[u]=1LL;
        for (i=point[u];i;i=next[i]){
            if ((v=en[i])==ff) continue;
            dfs1(v,u,de+1);siz[u]+=siz[v];
            if (siz[v]>mas){mas=siz[v];son[u]=v;}
        }
    }
    void dfs2(int u,int anc){
        int i,j,v;top[u]=anc;
        id[tid[u]=++ti]=u;visit[u]=true;
        if (son[u]) dfs2(son[u],anc);
        for (i=point[u];i;i=next[i]){
            if (visit[v=en[i]]) continue;
            dfs2(v,v);
        }la[u]=ti;
    }
    void cha(int a,int b){
        change(1,1,n,tid[b]);
        while(top[a]!=top[b]){
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ++sizb[a];tch(1,1,n,tid[a]);
            a=fa[top[a]];
        }if (dep[a]>dep[b]) swap(a,b);
        ++sizb[b];tch(1,1,n,tid[b]);
    }
    LL ask(int a,int b){
        LL ans=0LL;
        if (son[b]) ans=(ans+dep[b]*asum(1,1,n,tid[son[b]],la[son[b]])%p)%p;
        while(top[a]!=top[b]){
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ans=(ans+task(1,1,n,tid[top[a]],tid[a]))%p;
            ans=((ans-dep[fa[top[a]]]*asum(1,1,n,tid[top[a]],la[top[a]])%p)%p+p)%p;
            a=fa[top[a]];
            if (son[a]) ans=(ans+dep[a]*asum(1,1,n,tid[son[a]],la[son[a]])%p)%p;
        }if (dep[a]>dep[b]) swap(a,b);
        ans=(ans+task(1,1,n,tid[a],tid[b]))%p;
        return ans;
    }
}tr;
int main(){
    int q,i,j,l,r,z;LL ci;scanf("%d%d",&n,&q);
    for (i=1;i<n;++i){scanf("%d",&j);add(j+1,i+1);}
    for (tot=0,i=1;i<=q;++i){
        scanf("%d%d%d",&li[i].x,&ri[i].x,&z);
        ++ri[i].x;li[i].z=ri[i].z=++z;
        li[i].po=ri[i].po=i;
        if (li[i].x) lr[++tot]=li[i];
        if (ri[i].x) lr[++tot]=ri[i];
    }tr.dfs1(1,0,1);tr.dfs2(1,1);
    sort(lr+1,lr+tot+1);
    for (l=i=1;i<=tot;){
        j=i;while(j<tot&&lr[j+1].x==lr[i].x) ++j;
        while(l<=lr[j].x) tr.cha(1,l++);
        for (;i<=j;++i){
            ci=tr.ask(1,lr[i].z);z=lr[i].po;
            if (lr[i].x==ri[z].x) ans[z]=(ans[z]+ci)%p;
            if (lr[i].x==li[z].x) ans[z]=((ans[z]-ci)%p+p)%p;
        }
    }for (i=1;i<=q;++i) printf("%I64d\n",ans[i]);
}
View Code

 还有一种更简单的方法:离线处理,每次插入的时候就是把这个点到根上所有点的权值+1,查询的时候就是这个点到根的链的权值和。(因为这里求的是深度之和,所以每个点lca以上的所有点都要加给答案)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!