今天学习了树链剖分并且做了几道很有意思的题。。。
树链剖分的大致思想就是把一棵树转化成一条链(一个序列),然
后在上面做一些处理,例如:线段树。树转链的方法大致类似于 dfs
序,但是多了一个重边的处理。
上水题。(题名自行google)
1.BZOJ1036 ZJOJ2008 树的统计Count
标准模板题,超级水0.0。。。。。。
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<stack> 4 #include<queue> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #define inf 0x3f3f3f3f 10 #define ll long long 11 #define maxn 30005 12 #define lson u<<1,l,mid 13 #define rson u<<1|1,mid+1,r 14 using namespace std; 15 int w[maxn],head[maxn],tid[maxn],size[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],ecnt=1,cnt; 16 17 struct edge{ 18 int v,next; 19 }e[maxn*2]; 20 21 void adde(int u,int v){ 22 e[ecnt].v=v; 23 e[ecnt].next=head[u]; 24 head[u]=ecnt++; 25 } 26 27 void dfs1(int u,int pre){ 28 dep[u]=dep[pre]+1; 29 fa[u]=pre; 30 size[u]=1; 31 int msum=0; 32 for(int i=head[u];i;i=e[i].next){ 33 int v=e[i].v; 34 if(v==pre)continue; 35 dfs1(v,u); 36 size[u]+=size[v]; 37 if(size[v]>msum){ 38 msum=size[v]; 39 son[u]=v; 40 } 41 } 42 } 43 44 void dfs2(int u,int anc){ 45 tid[u]=++cnt; 46 top[u]=anc; 47 id[cnt]=u; 48 if(son[u])dfs2(son[u],anc); 49 for(int i=head[u];i;i=e[i].next){ 50 int v=e[i].v; 51 if(v==son[u]||v==fa[u])continue; 52 dfs2(v,v); 53 } 54 } 55 56 struct node{ 57 int l,r,ma,sum; 58 }t[4*maxn]; 59 60 void update(int u){ 61 t[u].sum=t[u<<1].sum+t[u<<1|1].sum; 62 t[u].ma=max(t[u<<1].ma,t[u<<1|1].ma); 63 } 64 65 void build(int u,int l,int r){ 66 t[u].l=l; 67 t[u].r=r; 68 if(l==r){ 69 t[u].sum=t[u].ma=w[id[l]]; 70 return; 71 } 72 int mid=(l+r)>>1; 73 build(lson); 74 build(rson); 75 update(u); 76 } 77 78 int askmax(int u,int l,int r){ 79 if(t[u].r==r&&t[u].l==l)return t[u].ma; 80 int mid=(t[u].l+t[u].r)>>1; 81 if(r<=mid)return askmax(u<<1,l,r); 82 if(l>mid)return askmax(u<<1|1,l,r); 83 else return max(askmax(u<<1,l,mid),askmax(u<<1|1,mid+1,r)); 84 } 85 86 int asksum(int u,int l,int r){ 87 if(t[u].r==r&&t[u].l==l)return t[u].sum; 88 int mid=(t[u].l+t[u].r)>>1; 89 if(r<=mid)return asksum(u<<1,l,r); 90 if(l>mid)return asksum(u<<1|1,l,r); 91 else return asksum(u<<1,l,mid)+asksum(u<<1|1,mid+1,r); 92 } 93 94 int findsum(int u,int v){ 95 int fu=top[u],fv=top[v]; 96 int tmp=0; 97 while(fu!=fv){ 98 if(dep[fu]<dep[fv]){ 99 swap(fu,fv); 100 swap(u,v); 101 } 102 tmp+=asksum(1,tid[fu],tid[u]); 103 u=fa[fu]; 104 fu=top[u]; 105 } 106 if(dep[u]>dep[v])swap(u,v); 107 return tmp+asksum(1,tid[u],tid[v]); 108 } 109 110 int findmax(int u,int v){ 111 int fu=top[u],fv=top[v]; 112 int tmp=-99999999; 113 while(fu!=fv){ 114 if(dep[fu]<dep[fv]){ 115 swap(fu,fv); 116 swap(u,v); 117 } 118 tmp=max(tmp,askmax(1,tid[fu],tid[u])); 119 u=fa[fu]; 120 fu=top[u]; 121 } 122 if(dep[u]>dep[v])swap(u,v); 123 return max(tmp,askmax(1,tid[u],tid[v])); 124 } 125 126 void change(int u,int k,int val){ 127 if(t[u].l==k&&t[u].r==k){ 128 t[u].ma=t[u].sum=val; 129 return; 130 } 131 int mid=(t[u].l+t[u].r)>>1; 132 if(k<=mid)change(u<<1,k,val); 133 else change(u<<1|1,k,val); 134 update(u); 135 } 136 137 int main(){ 138 int n,m; 139 scanf("%d",&n); 140 int a,b; 141 for(int i=1;i<n;i++)scanf("%d%d",&a,&b),adde(a,b),adde(b,a); 142 for(int i=1;i<=n;i++)scanf("%d",&w[i]),t[i].ma=-99999999; 143 dfs1(1,0); 144 dfs2(1,1); 145 build(1,1,n); 146 scanf("%d",&m); 147 for(int i=1;i<=m;i++){ 148 char s[100]; 149 scanf("%s",s); 150 scanf("%d%d",&a,&b); 151 if(s[0]=='C')change(1,tid[a],b); 152 else if(!strcmp(s,"QMAX"))printf("%d\n",findmax(a,b)); 153 else printf("%d\n",findsum(a,b)); 154 } 155 return 0; 156 }