树链剖分初步 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 */
- 树链剖分初步 spoj 375 hdu 3966 codeforces 191C
- 树链剖分 模板+HDU 3966 + SPOJ 375 【树剖入门】
- spoj 375 (树链剖分)
- SPOJ 375 树链剖分
- 【转】SPOJ 375 树链剖分
- spoj 375 树链剖分模板
- SPOJ 375 树链剖分学习
- SPOJ 375 树链剖分
- SPOJ 375 树链剖分
- SPOJ 375 树链剖分
- SPOJ 375 树链剖分
- 树链剖分模板(spoj 375)
- 树链剖分(SPOJ 375)
- LCT spoj 375 树链剖分
- SPOJ 375 (树链剖分+线段树)
- SPOJ 375 (树链剖分+线段树)
- Spoj 375 QTREE(树链剖分)
- spoj 375
- codeforces 191 E 数据结构题
- uva 11983 求矩形覆盖k次以上的面积并
- codeforces 122
- CF 85D 五颗线段树
- poj 2785 哈希!!!
- 树链剖分初步 spoj 375 hdu 3966 codeforces 191C
- codeforces 123 div2
- STL序列式容器和关联式容器
- CF 8 A
- Never underestimate the heart of a champion
- 今天在CSDN开博了,记录技术学习心得
- Codeforces Round #124 (Div. 2) (Div.1)
- 程序员的第一篇博客
- 有更新 浙大月赛 ZOJ Monthly, June 2012 on June 24