树链剖分
来源:互联网 发布:广电网络移机 编辑:程序博客网 时间:2024/04/28 19:42
定义:
1.重边:记 Size(U ) 表示以 U 为根的子树的结点个数,令 V 为 U 的儿子中
Size 最大的一个,那么我们称边 (U ,V ) 为重边,其余边为轻边。
2.重链:全都由重边组成的链称为重链。轻链同理定义
性质:
1.如果 (U ,V ) 为轻边,则
2.从根到某一点的路径上轻边的个数不大于 O(log N )
3.从根到某一点的路径上重链的条数不大于O(logN)
由以上性质可以将链
SPOJ QTREE
题意:点修改边权,链询问边权最大值
#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<cmath>#include<string.h>#include<math.h>#define mem(a,b) memset(a,b,sizeof(a))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int maxn = 20000+10;int t,n;char ch[10];int a[maxn],b[maxn],c[maxn];struct node{ int v,nx; }e[maxn<<2];int hd[maxn],tt;void add(int u,int v){ e[tt].v=v,e[tt].nx=hd[u],hd[u]=tt++;}//initint f[maxn],son[maxn],num[maxn],tp[maxn],id[maxn],d[maxn],p;void dfs1(int u,int fa,int dep){ num[u]=1,f[u]=fa,d[u]=dep; int tn=0; for(int i=hd[u];i!=-1;i=e[i].nx){ int v=e[i].v; if(v==fa) continue; dfs1(v,u,dep+1); num[u]+=num[v]; if(num[v]>tn) { tn=num[v],son[u]=v; } }}void dfs2(int u,int tpu){ tp[u]=tpu,id[u]=p++; if(son[u]!=-1) dfs2(son[u],tpu); for(int i=hd[u];i!=-1;i=e[i].nx){ int v=e[i].v; if(v==f[u]||v==son[u]) continue; dfs2(v,v); }}void init(){ mem(hd,-1),tt=p=0,mem(son,-1);}//Segment treeint Max[maxn<<2];void pushup(int rt){ Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); }void build(int l,int r,int rt){ if(l==r) { Max[rt]=0; return; } int m=(l+r)>>1; build(lson),build(rson); pushup(rt);}void update(int p,int x,int l,int r,int rt){ if(l==r) { Max[rt]=x; return; } int m=(l+r)>>1; if(p<=m) update(p,x,lson); else update(p,x,rson); pushup(rt);}int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) return Max[rt]; int m=(l+r)>>1,tmp=0; if(L<=m) tmp=max(tmp,query(L,R,lson)); if(R>m) tmp=max(tmp,query(L,R,rson)); return tmp;}//queryint Find(int u,int v){ int uu=tp[u],vv=tp[v],tans=0; while(uu!=vv){ if(d[uu]<d[vv]) swap(uu,vv),swap(u,v); tans=max(tans,query(id[uu],id[u],0,p-1,1)); u=f[uu],uu=tp[u]; } if(u==v) return tans; if(d[u]>d[v]) swap(u,v); return max(tans,query(id[son[u]],id[v],0,p-1,1));}int main(){ //freopen("a.txt","r",stdin); scanf("%d",&t); while(t--){ scanf("%d",&n); init(); for(int i=1;i<n;i++){ scanf("%d%d%d",&a[i],&b[i],&c[i]); add(a[i],b[i]),add(b[i],a[i]); } dfs1(1,0,1); dfs2(1,1); build(0,p-1,1); for(int i=1;i<n;i++){ if(d[a[i]]<d[b[i]]) swap(a[i],b[i]); update(id[a[i]],c[i],0,p-1,1); } while(scanf("%s",ch)!=EOF){ if(ch[0]=='D') break; int x,y; scanf("%d%d",&x,&y); if(ch[0]=='C') update(id[a[x]],y,0,p-1,1); else printf("%d\n",Find(x,y)); } } return 0;}
hdu5458
题意:在一个n边m点无向图(含重边和自环)中给出两种操作:
1.删除一条边
2.询问任意两点u和v的割边数量
解法:先找出无向图的dfs树,对于非树边,可以考虑成在树中添边的过程。添加一条边后,那么整条链上的边都不再是割边了。如果把后面的删边改成添边,那么恰好这两种操作就统一为添边操作。题意叙述改成:在一棵n点的树中给出两种操作:
1.添加一条边
2.询问任意两点u和v的割边数量
先将所有边赋值为1,添加
#include<iostream>#include<cstdio>#include<cstring>#define N maxn#define PII pair<int,int>#include<map>#include<vector>#define MP make_pair#include<map>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int maxn = 100000+10;int t,n,m,q;struct node{ int v,nxt;}e[maxn<<2];int head[maxn],tot;map<PII,int> ma;int a[maxn],b[maxn];int x[maxn],y[maxn],z[maxn];int bri[2][maxn],cnt;int vis[maxn],f[maxn],son[maxn],num[maxn],tp[maxn],id[maxn],d[maxn],p;int ans[maxn],cnt2;void add(int u,int v){ e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;}//Segment Treeint Sum[maxn<<2],cg[maxn<<2];void pushup(int rt) { Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; }void pushdown(int rt,int l,int r){ if(l==r) return; if(cg[rt]!=-1){ int m=(l+r)>>1; cg[rt<<1]=cg[rt<<1|1]=cg[rt]; Sum[rt<<1]=(m-l+1)*cg[rt]; Sum[rt<<1|1]=(r-m)*cg[rt]; cg[rt]=-1; }}void build(int l,int r,int rt){ cg[rt]=-1; if(l==r) { Sum[rt]=1; return; } int m=(l+r)>>1; build(lson),build(rson); pushup(rt);}void change(int L,int R,int x,int l,int r,int rt){ if(L<=l&&r<=R){ cg[rt]=x,Sum[rt]=(r-l+1)*x; return; } pushdown(rt,l,r); int m=(l+r)>>1; if(L<=m) change(L,R,x,lson); if(R>m) change(L,R,x,rson); pushup(rt);}int qsum(int L,int R,int l,int r,int rt){ int sum=0; if(L<=l&&r<=R) return Sum[rt]; pushdown(rt,l,r); int m=(l+r)>>1; if(L<=m) sum+=qsum(L,R,lson); if(R>m) sum+=qsum(L,R,rson); return sum;}//L_W(树链剖分)void solvechange(int u,int v,int x){ while(tp[u]!=tp[v]){ if(d[tp[u]]>d[tp[v]]) swap(u,v); change(id[tp[v]],id[v],x,1,n,1); v=f[tp[v]]; } if(u==v) return; if(d[u]>d[v]) swap(u,v); change(id[son[u]],id[v],x,1,n,1);}int solvesum(int u,int v){ int sm=0; while(tp[u]!=tp[v]){ if(d[tp[u]]>d[tp[v]]) swap(u,v); sm+=qsum(id[tp[v]],id[v],1,n,1); v=f[tp[v]]; } if(u==v) return sm; if(d[u]>d[v]) swap(u,v); sm+=qsum(id[u]+1,id[v],1,n,1); return sm;}void dfs1(int u,int fa,int dep){ num[u]=1,f[u]=fa,d[u]=dep,vis[u]=1; int tn=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].v; if(v==fa) continue; if(vis[v]) { bri[0][cnt]=u,bri[1][cnt++]=v; continue; }//记录非树边 dfs1(v,u,dep+1); num[u]+=num[v]; if(num[v]>tn) { tn=num[v],son[u]=v; } }}void dfs2(int u,int tpu){ tp[u]=tpu,id[u]=++p; if(son[u]!=-1) dfs2(son[u],tpu); for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].v; if(f[v]!=u||v==son[u]) continue;//非重链儿子节点 dfs2(v,v); }}int main(){ //freopen("a.txt","r",stdin); scanf("%d",&t); int cas=0; while(t--){ ma.clear(); scanf("%d%d%d",&n,&m,&q); memset(head,-1,sizeof(head)); tot=0; memset(son,-1,sizeof(son)); p=0; memset(vis,0,sizeof(vis)); cnt=0; for(int i=1;i<=m;i++){ scanf("%d%d",&a[i],&b[i]); if(a[i]==b[i]) continue; if(a[i]>b[i]) swap(a[i],b[i]); if(ma.find(MP(a[i],b[i]))==ma.end()) ma[MP(a[i],b[i])]=1; else ma[MP(a[i],b[i])]++; } for(int i=1;i<=q;i++){ scanf("%d%d%d",&x[i],&y[i],&z[i]); if(y[i]==z[i]) continue; if(y[i]>z[i]) swap(y[i],z[i]); if(x[i]==1) ma[MP(y[i],z[i])]--; } for(int i=1;i<=m;i++){ if(a[i]==b[i]) continue; int tmp=ma[MP(a[i],b[i])]; if(tmp==0||tmp==-1) continue;//被删除或者已添加 else{ add(a[i],b[i]),add(b[i],a[i]); if(tmp>1) bri[0][cnt]=a[i],bri[1][cnt++]=b[i];//记录重边 ma[MP(a[i],b[i])]=-1; } } printf("Case #%d:\n",++cas); build(1,n,1); dfs1(1,0,0),dfs2(1,1); for(int i=0;i<cnt;i++){ int u=bri[0][i],v=bri[1][i]; if(u==v) continue; solvechange(u,v,0); } cnt2=0; for(int i=q;i>=1;i--){ if(x[i]==1){ if(y[i]==z[i]) continue; solvechange(y[i],z[i],0); } else{ if(y[i]==z[i]) ans[cnt2++]=0; else{ ans[cnt2++]=solvesum(y[i],z[i]); } } } for(int i=cnt2-1;i>=0;i--) printf("%d\n",ans[i]); } return 0;}
bzoj4034
题意:树上支持三种操作:
1.修改点权值
2.修改子树点权值
3.询问点到跟节点路径权值和
解法:记录mx[u]:u子树点的最大标号,修改子树权值相当于修改[id[u],mx[u]]区间点权值
注意与边权不同,判断u==v时,需要加上该点的权值!
#include<iostream>#include<cstdio>#include<cstring>#define N maxn#define PII pair<int,int>#include<map>#include<vector>#define MP make_pair#include<map>#define ll long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 1e5+10;int n,m;vector<int> g[maxn];int w[maxn];//Segment_Treell ad[maxn<<2],Sum[maxn<<2];void pushup(int rt){ Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; }void pushdown(int rt,int len){ if(len==1) return; if(ad[rt]){ ad[rt<<1]+=ad[rt],ad[rt<<1|1]+=ad[rt]; int l=(len+1)/2,r=len/2; Sum[rt<<1]+=ad[rt]*l; Sum[rt<<1|1]+=ad[rt]*r; ad[rt]=0; }}void build(int l,int r,int rt){ ad[rt]=0; if(l==r) { Sum[rt]=0; return; } int m=(l+r)>>1; build(lson),build(rson); pushup(rt);}void add(int L,int R,int x,int l,int r,int rt){ if(L<=l&&r<=R) { ad[rt]+=x,Sum[rt]=(Sum[rt]+(ll)x*(ll)(r-l+1)); return; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) add(L,R,x,lson); if(R>m) add(L,R,x,rson); pushup(rt);}ll qsum(int L,int R,int l,int r,int rt){ pushdown(rt,r-l+1); ll sm=0; if(L<=l&&r<=R) return Sum[rt]; int m=(l+r)>>1; if(L<=m) sm+=qsum(L,R,lson); if(R>m) sm+=qsum(L,R,rson); return sm;}//L_Wint f[maxn],num[maxn],d[maxn],tp[maxn],id[maxn],mx[maxn],son[maxn],p;void dfs1(int u,int fa,int dep){ num[u]=1,f[u]=fa,d[u]=dep; //printf("%d %d\n",u,f[u]); int tn=0; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v==fa) continue; dfs1(v,u,dep+1); num[u]+=num[v]; if(num[v]>tn) { tn=num[v],son[u]=v; } }}void dfs2(int u,int tpu){ tp[u]=tpu,id[u]=mx[u]=++p; if(son[u]!=-1) { dfs2(son[u],tpu); mx[u]=max(mx[u],mx[son[u]]); } for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v==f[u]||v==son[u]) continue; dfs2(v,v); mx[u]=max(mx[u],mx[v]); }}ll solvesum(int u,int v){ ll sm=0; while(tp[u]!=tp[v]){ if(d[tp[u]]>d[tp[v]]) swap(u,v);//比较tp的深度大小!! sm+=qsum(id[tp[v]],id[v],1,n,1); v=f[tp[v]]; } if(u==v) { sm+=qsum(id[u],id[u],1,n,1); return sm; }//点权需要加上相同点的点权!! if(d[u]>d[v]) swap(u,v); sm+=qsum(id[u],id[v],1,n,1); return sm;}int main(){ //freopen("a.txt","r",stdin); while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++) { scanf("%d",&w[i]); g[i].clear(); } int kind,u,v; for(int i=1;i<=n-1;i++){ scanf("%d%d",&u,&v); g[u].push_back(v),g[v].push_back(u); } memset(son,-1,sizeof(son)); p=0; build(1,n,1); dfs1(1,0,0),dfs2(1,1); for(int i=1;i<=n;i++) add(id[i],id[i],w[i],1,n,1); while(m--){ scanf("%d",&kind); if(kind==1){ scanf("%d%d",&u,&v); add(id[u],id[u],v,1,n,1); } else if(kind==2){ scanf("%d%d",&u,&v); add(id[u],mx[u],v,1,n,1); } else{ scanf("%d",&u); printf("%lld\n",solvesum(1,u)); } } } return 0;}
0 0
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- Android重力感应飘树叶,晃动掉元宝
- 浅谈HTTP中Get与Post的区别
- 一致性选择
- 2015-8-19数据结构学习-哈夫曼树
- TCP 的那些事儿(上)
- 树链剖分
- 操作系统——面试知识点精华
- gold coin1+2+2+3+3+3+4+4+4+4+。。。。
- VNC源码研究(一)VNC简介
- 去除TableView的边框线. (分割线 ,下划线就这个意思)
- 背包之01背包、完全背包、多重背包详解
- [Ptrace]Linux内存替换(六)动态链接库函数替换
- resource net/sf/antcontrib/antlib.xml. It could not be found.
- iOS常用的函数和常数