首页 > 代码库 > HDU 5044 (树链剖分+树状数组+点/边改查)

HDU 5044 (树链剖分+树状数组+点/边改查)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044

题目大意:修改链上点,修改链上的边。查询所有点,查询所有边。

解题思路

2014上海网赛的变态树链剖分模板题。将以往树链剖分的点&边修改和查询合在一起之后,难度上去不少。

第一个卡人点是读入优化。

第二个卡人点是树状数组。由于要查询所有点,如果使用线段树,每次都要扫到底层才能取出点值,必T无疑。

然后使用树状数组之后,树链剖分的点/边修改写法有些变动。

点查询变化不大。

边查询只要查询一下dep(u,v)大的那一端。

 

具体变化请仔细看代码。

 

#pragma comment(linker, "/STACK:1024000000,1024000000")#include "cstdio"#include "cstring"#include "iostream"using namespace std;#define maxn 100005template <class T>inline bool read(T &ret){    char c;    int sgn;    if(c=getchar(),c==EOF) return 0; //EOF    while(c!=-&&(c<0||c>9)) c=getchar();    sgn=(c==-)?-1:1;    ret=(c==-)?0:(c-0);    while(c=getchar(),c>=0&&c<=9) ret=ret*10+(c-0);    ret*=sgn;    return 1;}int s[maxn],dep[maxn],w[maxn],fa[maxn],top[maxn],son[maxn],tol,cnt,n,head[maxn];struct Edge{    int u,v,c;}edge[maxn];struct EDGE{    int next,to;}e[2*maxn];void addedge(int u,int v){    e[tol].to=v;    e[tol].next=head[u];    head[u]=tol++;}void dfs1(int u,int pre,int d){    s[u]=1;fa[u]=pre;dep[u]=d;son[u]=-1;    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].to;        if(v==pre) continue;        dfs1(v,u,d+1);        s[u]+=s[v];        if(son[u]!=-1||s[v]>s[son[u]]) son[u]=v;    }}void dfs2(int u,int tp){    w[u]=++cnt;top[u]=tp;    if(son[u]!=-1) dfs2(son[u],tp);    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].to;        if(v!=son[u]&&v!=fa[u]) dfs2(v,v);    }}//Binary-Indexed-Tree type:0-point,1-edgeint psum[maxn],esum[maxn];inline int lowbit(int x) {return x&(-x);}int sum(int x,int type){    int ret=0;    while(x>0)    {        if(!type) ret+=psum[x];        else ret+=esum[x];        x-=lowbit(x);    }    return ret;}void add(int x,int d,int type){    while(x<=n)    {        if(!type) psum[x]+=d;        else esum[x]+=d;        x+=lowbit(x);    }}void p_Change(int x,int y,int v){    while(top[x]!=top[y])    {        if(dep[top[x]]<dep[top[y]]) swap(x,y);        add(w[top[x]],v,0);        add(w[x]+1,-v,0);        x=fa[top[x]];    }    if(dep[x]>dep[y]) swap(x,y);    add(w[x],v,0);    add(w[y]+1,-v,0);}void e_Change(int x,int y,int v){    while(top[x]!=top[y])    {        if(dep[top[x]]<dep[top[y]]) swap(x,y);        add(w[top[x]],v,1);        add(w[x]+1,-v,1);        x=fa[top[x]];    }    if(dep[x]>dep[y]) swap(x,y);    if(x!=y) //这个判断非常重要,没有的话T死你    {        add(w[son[x]],v,1);        add(w[y]+1,-v,1);    }}int main(){    //freopen("in.txt","r",stdin);    int T,u,v,c,m,no=0;    char cmd[10];    read(T);    while(T--)    {        memset(head,-1,sizeof(head));        memset(esum,0,sizeof(esum));        memset(psum,0,sizeof(psum));        tol=cnt=0;        read(n);read(m);        for(int i=1;i<n;i++)        {            read(edge[i].u);read(edge[i].v);            addedge(edge[i].u,edge[i].v);            addedge(edge[i].v,edge[i].u);        }        dfs1(1,1,1);        dfs2(1,1);        for(int i=1;i<n;i++)          if(dep[edge[i].u]<dep[edge[i].v]) swap(edge[i].u,edge[i].v);        while(m--)        {            scanf("%s",cmd);            read(u);read(v);read(c);            if(cmd[3]==1) p_Change(u,v,c);            if(cmd[3]==2) e_Change(u,v,c);        }        printf("Case #%d:\n",++no);        for(int i=1;i<=n;i++) {if(i>=2) printf(" ");printf("%d",sum(w[i],0));}        printf("\n");        for(int i=1;i<n;i++) {if(i>=2) printf(" ");printf("%d",sum(w[edge[i].u],1));}        printf("\n");    }}

 

118245252014-10-08 17:34:00Accepted50443718MS11576K3384 BC++Physcal

HDU 5044 (树链剖分+树状数组+点/边改查)