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

这几个题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|1
const 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;
}
/*
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
1
3
1
7
1 2 1
1 3 2
2 4 3
2 5 4
3 6 5
3 7 6
Query 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|1
const 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|1
typedef __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         else
138         {
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;//在此处发现了我代码的重大bug
157            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     else
167     {
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             else
203             {
204                 scanf("%d",&a);a--;
205                 printf("%d\n",solve(a));
206             }
207         }
208     }
209     return 0;
210 }
211 /*
212 3 2 5
213 1 2 3
214 2 1
215 2 3
216 I 1 3 5
217 Q 2
218 D 1 2 2
219 Q 1 
220 Q 3
221 */
posted @ 2012-06-08 20:12  Because Of You  Views(2046)  Comments(0Edit  收藏  举报