树链剖分初步 spoj 375 hdu 3966 codeforces 191C

来源:互联网 发布:excel跨工作簿引用数据 编辑:程序博客网 时间:2024/06/08 05:16

这几个题A的好不容易啊!!!留念一下

树链剖分初体验:

 可以解决 询问一棵树上点对间的简单路径的长度  边权的最大值最小值,并支持动态修改边权,注意,树的形态始终没有改变

另外,点权的变化可以转换为边权,即每个点的点权都转移到与父节点的边之间的边权上,根节点特殊判断

 

spoj 375

贴上我巨搓无比的代码,虽然没有别人的短,虽然没有别人的快,但是毕竟它A了 -_-!!!

View Code
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 20010;const int inf = ~0u>>2;int M[maxn<<2];struct node{    int s,t,w,next;}edge[maxn*2];int E,n;int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , dep[maxn] , rev[maxn] , num[maxn] , cost[maxn];int Seg_size;inline void Max(int &x,int y){if(x<y) x=y;}int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void add_edge(int s,int t,int w){    edge[E].w=w;    edge[E].s=s;    edge[E].t=t;    edge[E].next=head[s];    head[s]=E++;}void dfs(int u,int f){    int mx=-1,e=-1;    size[u]=1;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].t;        if(v==f) continue;        dep[v]=dep[u]+1;        rev[v]=i^1;        dfs(v,u);        size[u]+=size[v];        if(size[v]>mx)        {            mx=size[v];            e=i;        }    }    heavy[u]=e;    if(e!=-1)  fa[edge[e].t]=u;}inline void pushup(int rt){    M[rt]=max(M[rt<<1],M[rt<<1|1]);}void build(int l,int r,int rt){    M[rt]=inf;    if(l==r){        return ;    }    int m=(l+r)>>1;    build(lson);    build(rson);}void update(int p,int val,int l,int r,int rt){    if(l==r){       M[rt]=val;       return ;    }    int m=(l+r)>>1;    if(p<=m) update(p,val,lson);    else update(p,val,rson);    pushup(rt);}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return M[rt];    }    int m=(l+r)>>1;    int ret=0;    if(L<=m) ret=max(ret,query(L,R,lson));    if(R>m) ret=max(ret,query(L,R,rson));    return ret;}void prepare(){    build(1,n-1,1);    memset(num,-1,sizeof(num));    dep[0]=0;Seg_size=0;    for(int i=0;i<n;i++) fa[i]=i;    dfs(0,0);        for(int i=0;i<n;i++)    {        if(heavy[i]==-1)        {            int pos=i;            while(pos && edge[heavy[edge[rev[pos]].t]].t == pos)            {                int t=rev[pos];                num[t]=num[t^1]=++Seg_size;                update(Seg_size,edge[t].w,1,n-1,1);                pos=edge[t].t;            }        }    }}void change(int edge_id,int val){    if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val;    else update(num[edge_id],val,1,n-1,1);}int calc(int u,int lca){    int ans=-inf;int vi=0;    while(u!=lca)    {        vi++;        if(vi==10) break;        int r=rev[u];        if(num[r]==-1) Max(ans,edge[r].w),u=edge[r].t;        else         {            int p=fa[u];            if(dep[p] < dep[lca]) p=lca;            int l=num[r];            int r=num[heavy[p]];            Max(ans,query(l,r,1,n-1,1));            u=p;        }    }    return ans;}int lca(int u,int v){    while(1)    {        int a=find(u),b=find(v);        if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上        else if(dep[a]>=dep[b]) u=edge[rev[a]].t;        else v=edge[rev[b]].t;    }}int solve(int u,int v){    int p=lca(u,v);    return max(calc(u,p),calc(v,p));}int main(){    int t,i,a,b,c;    scanf("%d",&t);    while(t--)    {        memset(head,-1,sizeof(head));        E=0;        scanf("%d",&n);        for(i=0;i<n-1;i++)        {            scanf("%d%d%d",&a,&b,&c);a--;b--;            add_edge(a,b,c);            add_edge(b,a,c);        }        prepare();        char op[20];        while(scanf("%s",op)!=EOF && strcmp(op,"DONE"))        {            if(op[0]=='C')            {                scanf("%d%d",&a,&c);                change((a-1)*2,c);            }            else             {                scanf("%d%d",&a,&b);                printf("%d\n",solve(a-1,b-1));            }        }    }    return 0;}/*131 2 12 3 2QUERY 1 2CHANGE 1 3QUERY 1 2DONE13171 2 11 3 22 4 32 5 43 6 53 7 6Query 1 7*/

 

CF 191C

这题有更简单的 O(n)做法,这里为了锻炼树链剖分

View Code
/*树链剖分,输入边权,p个操作,给u,v间的简单路径的边权都加上1最后输出所有边的边权*/#include<cstdio>#include<cstring>#include<stack>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 200010;const int inf = ~0u>>2;int M[maxn<<2];int add[maxn<<2];struct node{    int s,t,w,next;}edge[maxn*2];int E,n;int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , vis[maxn];int dep[maxn] , rev[maxn] , num[maxn] ;int Seg_size;int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void add_edge(int s,int t,int w){    edge[E].w=w;    edge[E].s=s;    edge[E].t=t;    edge[E].next=head[s];    head[s]=E++;}void dfs(int u,int f){    int mx=-1,e=-1;    size[u]=1;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].t;           if(v==f) continue;         dep[v]=dep[u]+1;        rev[v]=i^1;        dfs(v,u);        size[u]+=size[v];        if(size[v]>mx)        {            mx=size[v];            e=i;        }    }    heavy[u]=e;    if(e!=-1)  fa[edge[e].t]=u;}inline void pushup(int rt){    M[rt]=M[rt<<1]+M[rt<<1|1];}void pushdown(int rt,int m){    if(add[rt]){        add[rt<<1]+=add[rt];        add[rt<<1|1]+=add[rt];        M[rt<<1]+=add[rt]*(m-(m>>1));        M[rt<<1|1]+=add[rt]*(m>>1);        add[rt]=0;    }}void build(int l,int r,int rt){    M[rt]=add[rt]=0;    if(l==r){        return ;    }    int m=(l+r)>>1;    build(lson);    build(rson);}void update(int L,int R,int val,int l,int r,int rt){    if(L<=l&&r<=R){        M[rt]+=val;        add[rt]+=val;        return ;    }    pushdown(rt,r-l+1);    int m=(l+r)>>1;    if(L<=m) update(L,R,val,lson);    if(R>m) update(L,R,val,rson);    pushup(rt);}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return M[rt];    }    pushdown(rt,r-l+1);    int m=(l+r)>>1;    int ret=0;    if(L<=m) ret+=query(L,R,lson);    if(R>m) ret+=query(L,R,rson);    return ret;}void prepare(){    int i;    build(1,n,1);    memset(num,-1,sizeof(num));    dep[0]=0;Seg_size=0;    for(i=0;i<n;i++) fa[i]=i;    dfs(0,0);      for(i=0;i<n;i++)    {        if(heavy[i]==-1)        {            int pos=i;            while(pos && edge[heavy[edge[rev[pos]].t]].t == pos)            {                int t=rev[pos];                num[t]=num[t^1]=++Seg_size;//printf("pos=%d  val=%d t=%d\n",Seg_size,edge[t].w,t);                update(Seg_size,Seg_size,edge[t].w,1,n,1);                pos=edge[t].t;            }        }    }}int lca(int u,int v){    while(1)    {        int a=find(u),b=find(v);        if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上        else if(dep[a]>=dep[b]) u=edge[rev[a]].t;        else v=edge[rev[b]].t;    }}void CH(int u,int lca,int val){    while(u!=lca)    {        int r=rev[u];        if(num[r]==-1) edge[r^1].w+=val,edge[r].w+=val,u=edge[r].t;        else        {            int p=fa[u];            if(dep[p] < dep[lca]) p=lca;            int l=num[r];            r=num[heavy[p]];            update(l,r,val,1,n,1);            u=p;        }    }}void change(int u,int v,int val){    int p=lca(u,v);    CH(u,p,val);    CH(v,p,val);}int solve(int id){    int r=id;    if(num[r]==-1) return edge[r].w;    else return query(num[r],num[r],1,n,1);}int main(){    int t,i,a,b,c,m,ca=1,p;    while(scanf("%d",&n)!=EOF)    {        memset(head,-1,sizeof(head));        E=0;        for(i=0;i<n-1;i++)        {            scanf("%d%d",&a,&b);a--;b--;            add_edge(a,b,0);            add_edge(b,a,0);        }        prepare();        scanf("%d",&p);        while(p--)        {            scanf("%d%d",&a,&b);a--;b--;            change(a,b,1);        }        for(i=0;i<n-1;i++)        {            if(i!=0) printf(" ");            printf("%d",solve(2*i));        }        puts("");    }    return 0;}

 

 FZU 2082过路费

单边修改,点对求和,如果对应到线段树就是单点更新(如果是重边)  区间求和

View Code
#include<cstdio>#include<cstring>#include<stack>#include<algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef __int64 lld;const int maxn = 200010;const int inf = ~0u>>2;lld M[maxn<<2];struct node{    int s,t,w,next;}edge[maxn*2];int E,n;int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , vis[maxn];int dep[maxn] , rev[maxn] , num[maxn] ;int Seg_size;int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void add_edge(int s,int t,int w){    edge[E].w=w;    edge[E].s=s;    edge[E].t=t;    edge[E].next=head[s];    head[s]=E++;}void dfs(int u,int f){    int mx=-1,e=-1;    size[u]=1;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].t;           if(v==f) continue;         dep[v]=dep[u]+1;        rev[v]=i^1;        dfs(v,u);        size[u]+=size[v];        if(size[v]>mx){            mx=size[v];            e=i;        }    }    heavy[u]=e;    if(e!=-1)  fa[edge[e].t]=u;}inline void pushup(int rt){    M[rt]=M[rt<<1]+M[rt<<1|1];}void build(int l,int r,int rt){    M[rt]=0;    if(l==r) return ;    int m=(l+r)>>1;    build(lson);    build(rson);}void update(int p,int val,int l,int r,int rt){    if(l==r){       M[rt]=val;       return ;    }    int m=(l+r)>>1;    if(p<=m) update(p,val,lson);    else update(p,val,rson);    pushup(rt);}lld query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R)  return M[rt];    int m=(l+r)>>1;    lld ret=0;    if(L<=m) ret+=query(L,R,lson);    if(R>m) ret+=query(L,R,rson);    return ret;}void prepare(){    build(1,n-1,1);    memset(num,-1,sizeof(num));    dep[0]=0;Seg_size=0;    for(int i=0;i<n;i++) fa[i]=i;    dfs(0,0);      for(int i=0;i<n;i++){        if(heavy[i]==-1){            int pos=i;            while(pos && edge[heavy[edge[rev[pos]].t]].t == pos){                int t=rev[pos];                num[t]=num[t^1]=++Seg_size;//printf("pos=%d  val=%d t=%d\n",Seg_size,edge[t].w,t);                update(Seg_size,edge[t].w,1,n-1,1);                pos=edge[t].t;            }        }    }}void change(int edge_id,int val){    if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val;    else update(num[edge_id],val,1,n-1,1);}lld calc(int u,int lca){    lld ans=0;    while(u!=lca){        int r=rev[u];        if(num[r]==-1) ans+=edge[r].w,u=edge[r].t;        else{            int p=fa[u];            if(dep[p] < dep[lca]) p=lca;            int l=num[r];            int r=num[heavy[p]];            ans+=query(l,r,1,n-1,1);            u=p;        }    }    return ans;}int lca(int u,int v){    while(1){        int a=find(u),b=find(v);        if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上        else if(dep[a]>=dep[b]) u=edge[rev[a]].t;        else v=edge[rev[b]].t;    }}lld solve(int u,int v){    int p=lca(u,v);    return  calc(u,p)+calc(v,p);}int main(){    int t,i,a,b,c,m,ca=1,p,w;    while(scanf("%d%d",&n,&m)!=EOF){        memset(head,-1,sizeof(head));        E=0;        for(i=0;i<n-1;i++) {            scanf("%d%d%d",&a,&b,&w);a--;b--;            add_edge(a,b,w);            add_edge(b,a,w);        }        prepare();        int op;        while(m--){            scanf("%d%d%d",&op,&a,&b);            if(op==0){                change((a-1)*2,b);            }            else {                a--;b--;                printf("%I64d\n",solve(a,b));            }        }        }    return 0;}

 

 

 

hdu  3966

这一题要模拟栈的,hdu可以设置栈的大小,为了测试我代码的正确性,我猥琐了一下(不然连对不对都不知道,增加debug的难度)

突然我的代码在长度上压过很多人 -_-

截个图

View Code
  1 #pragma comment(linker,"/STACK:100000000,100000000")  2 #include<cstdio>  3 #include<cstring>  4 #include<stack>  5 #include<algorithm>  6 using namespace std;  7 #define lson l,m,rt<<1  8 #define rson m+1,r,rt<<1|1  9 typedef int lld; 10 stack<int> ss; 11 const int maxn = 200010; 12 const int inf = ~0u>>2; 13 int M[maxn<<2]; 14 int add[maxn<<2]; 15 struct node{ 16     int s,t,w,next; 17 }edge[maxn*2]; 18 int E,n; 19 int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , vis[maxn]; 20 int dep[maxn] , rev[maxn] , num[maxn] , cost[maxn] ,w[maxn]; 21 int Seg_size; 22 inline void Max(int &x,int y){if(x<y) x=y;} 23 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} 24 void add_edge(int s,int t,int w) 25 { 26     edge[E].w=w; 27     edge[E].s=s; 28     edge[E].t=t; 29     edge[E].next=head[s]; 30     head[s]=E++; 31 } 32 void dfs(int u,int f) 33 { 34     int mx=-1,e=-1; 35     size[u]=1; 36     for(int i=head[u];i!=-1;i=edge[i].next) 37     { 38         int v=edge[i].t;    39         if(v==f) continue;  40         edge[i].w=edge[i^1].w=w[v]; 41         dep[v]=dep[u]+1; 42         rev[v]=i^1; 43         dfs(v,u); 44         size[u]+=size[v]; 45         if(size[v]>mx) 46         { 47             mx=size[v]; 48             e=i; 49         } 50     } 51     heavy[u]=e; 52     if(e!=-1)  fa[edge[e].t]=u; 53 } 54 inline void pushup(int rt){ 55     M[rt]=M[rt<<1]+M[rt<<1|1]; 56 } 57 void pushdown(int rt,int m){ 58     if(add[rt]){ 59         add[rt<<1]+=add[rt]; 60         add[rt<<1|1]+=add[rt]; 61         M[rt<<1]+=add[rt]*(m-(m>>1)); 62         M[rt<<1|1]+=add[rt]*(m>>1); 63         add[rt]=0; 64     } 65 } 66 void build(int l,int r,int rt){ 67     M[rt]=add[rt]=0; 68     if(l==r){ 69         return ; 70     } 71     int m=(l+r)>>1; 72     build(lson); 73     build(rson); 74 } 75 void update(int L,int R,int val,int l,int r,int rt){ 76     if(L<=l&&r<=R){ 77         M[rt]+=val; 78         add[rt]+=val; 79         return ; 80     } 81     pushdown(rt,r-l+1); 82     int m=(l+r)>>1; 83     if(L<=m) update(L,R,val,lson); 84     if(R>m) update(L,R,val,rson); 85     pushup(rt); 86 } 87 lld query(int L,int R,int l,int r,int rt){ 88     if(L<=l&&r<=R){ 89         return M[rt]; 90     } 91     pushdown(rt,r-l+1); 92     int m=(l+r)>>1; 93     lld ret=0; 94     if(L<=m) ret+=query(L,R,lson); 95     if(R>m) ret+=query(L,R,rson); 96     return ret; 97 } 98 void prepare() 99 {100     int i;101     build(1,n,1);102     memset(num,-1,sizeof(num));103     dep[0]=0;Seg_size=0;104     for(i=0;i<n;i++) fa[i]=i;105     dfs(0,0);  106     for(i=0;i<n;i++)107     {108         if(heavy[i]==-1)109         {110             int pos=i;111             while(pos && edge[heavy[edge[rev[pos]].t]].t == pos)112             {113                 int t=rev[pos];114                 num[t]=num[t^1]=++Seg_size;//printf("pos=%d  val=%d t=%d\n",Seg_size,edge[t].w,t);115                 update(Seg_size,Seg_size,edge[t].w,1,n,1);116                 pos=edge[t].t;117             }118         }119     }120 }121 int lca(int u,int v)122 {123     while(1)124     {125         int a=find(u),b=find(v);126         if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上127         else if(dep[a]>=dep[b]) u=edge[rev[a]].t;128         else v=edge[rev[b]].t;129     }130 }131 void CH(int u,int lca,int val)132 {133     while(u!=lca)134     {135         int r=rev[u];//printf("r=%d\n",r);136         if(num[r]==-1) edge[r].w+=val,u=edge[r].t;137         else138         {139             int p=fa[u];140             if(dep[p] < dep[lca]) p=lca;141             int l=num[r];142             r=num[heavy[p]];143             update(l,r,val,1,n,1);144             u=p;145         }146     }147 }148 void change(int u,int v,int val)149 {150     int p=lca(u,v);//    printf("p=%d\n",p);151     CH(u,p,val);152     CH(v,p,val);153     if(p){154         int r=rev[p];155        if(num[r]==-1) {156            edge[r^1].w+=val;//在此处发现了我代码的重大bug157            edge[r].w+=val;158        }159       else  update(num[r],num[r],val,1,n,1);160     }//根节点,特判 161     else w[p]+=val;162 }163 lld solve(int u)164 {165     if(!u) return w[u];//根节点,特判 166     else167     {168         int r=rev[u];169         if(num[r]==-1) return edge[r].w;170         else return query(num[r],num[r],1,n,1);171     }172 }173 int main()174 {175     int t,i,a,b,c,m,ca=1,p;176     while(scanf("%d%d%d",&n,&m,&p)!=EOF)177     {178         memset(head,-1,sizeof(head));179         E=0;180         for(i=0;i<n;i++) scanf("%d",&w[i]);181         for(i=0;i<m;i++)182         {183             scanf("%d%d",&a,&b);a--;b--;184             add_edge(a,b,0);185             add_edge(b,a,0);186         }187         prepare();188         char op[10];189         while(p--)190         {191             scanf("%s",&op);192             if(op[0]=='I')193             {194                 scanf("%d%d%d",&a,&b,&c);a--;b--;195                 change(a,b,c);196             }197             else if(op[0]=='D')198             {199                 scanf("%d%d%d",&a,&b,&c);a--;b--;200                 change(a,b,-c);201             }202             else203             {204                 scanf("%d",&a);a--;205                 printf("%d\n",solve(a));206             }207         }208     }209     return 0;210 }211 /*212 3 2 5213 1 2 3214 2 1215 2 3216 I 1 3 5217 Q 2218 D 1 2 2219 Q 1 220 Q 3221 */