1. 程式人生 > >BZOJ 4012 [HNOI2015]開店 (樹分治+二分)

BZOJ 4012 [HNOI2015]開店 (樹分治+二分)

題目大意:

給你一棵樹,邊有邊權,點有點權,有很多次詢問,求點權$\in[l,r]$的所有節點到某點$x$的距離之和,強制線上

感覺這個題應該放在動態點分之前做= =

套路方法和動態點分是一樣的

每次詢問,從$x$開始,沿著點分樹的樹鏈向上統計,計算當前點的點分樹的答案,然後去掉包含$x$的那棵點分子樹的答案

$x$節點在點分樹內的 所有祖先節點 對於答案的貢獻都有兩個部分

1.除了包含$x$的點分子樹 的所有權值$\in[l,r]$的節點到 當前祖先節點 的距離

2.合法節點數量*當前祖先節點到$x$的距離

而這道題是靜態的,不用每個節點都開線段樹,改成$vector$,每次都在上面二分就好了

具體實現

每個節點都開一個$vector$,設當前的點分節點是$x$,把$x$點分樹內的所有子節點推進去,按照點權排序,再統計一下到$x$距離的字首和

統計$[l,r]$的答案時,只需要在$vector$裡二分出右端點查詢dis的字首和,還要加上點數總和(即右端點下標) *當前 點分樹節點 到 詢問節點 的距離,再利用字首和容斥$calc(r)-calc(l-1)$即可

時間仍然是$O(nlog^{2}n)$,但空間變成了$O(nlogn)$

由於用了$vector$常數大的一批但我也懶得優化了

  1 #include <vector>
  2 #include <cstdio>
  3
#include <cstring> 4 #include <algorithm> 5 #define N1 150100 6 #define ll long long 7 #define dd double 8 #define inf 0x3f3f3f3f3f3f3f3fll 9 using namespace std; 10 11 int gint() 12 { 13 int ret=0,fh=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='
-')fh=-1;c=getchar();} 15 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 16 return ret*fh; 17 } 18 19 struct Edge{ 20 int to[N1<<1],nxt[N1<<1],val[N1<<1],head[N1],cte; 21 void ae(int u,int v,int w){ 22 cte++;to[cte]=v;val[cte]=w; 23 nxt[cte]=head[u];head[u]=cte;} 24 }e; 25 namespace tr{ 26 ll dis[N1];int dep[N1],ff[N1<<1][20],lg[N1<<1],st[N1<<1],tot; 27 void dfs1(int u,int dad) 28 { 29 st[u]=++tot; ff[tot][0]=u; 30 for(int j=e.head[u];j;j=e.nxt[j]) 31 { 32 int v=e.to[j]; if(v==dad) continue; 33 dis[v]=dis[u]+e.val[j]; dep[v]=dep[u]+1; 34 dfs1(v,u); ff[++tot][0]=u; 35 } 36 } 37 void get_st() 38 { 39 int i,j; 40 for(lg[1]=0,i=2;i<=tot;i++) lg[i]=lg[i>>1]+1; 41 for(j=1;j<=lg[tot];j++) 42 for(i=1;i+(1<<j)-1<=tot;i++) 43 ff[i][j]=dep[ ff[i][j-1] ] < dep[ ff[i+(1<<(j-1))][j-1] ] ? ff[i][j-1] : ff[i+(1<<(j-1))][j-1]; 44 } 45 ll Dis(int x,int y) 46 { 47 int tx=min(st[x],st[y]),ty=max(st[x],st[y]),L=ty-tx+1; 48 int fa=dep[ ff[tx][lg[L]] ] < dep[ ff[ty-(1<<lg[L])+1][lg[L]] ] ? ff[tx][lg[L]] : ff[ty-(1<<lg[L])+1][lg[L]]; 49 return dis[x]+dis[y]-2ll*dis[fa]; 50 } 51 void init(){dfs1(1,-1);get_st();} 52 }; 53 int n,m,ma; 54 int ms[N1],sz[N1],use[N1],fr[N1],fa[N1],a[N1],tsz,G; 55 void gra(int u,int dad) 56 { 57 sz[u]=1; ms[u]=0; 58 for(int j=e.head[u];j;j=e.nxt[j]) 59 { 60 int v=e.to[j]; if(v==dad||use[v]) continue; 61 gra(v,u); 62 sz[u]+=sz[v]; ms[u]=max(ms[u],sz[v]); 63 } 64 ms[u]=max(ms[u],tsz-sz[u]); 65 if(ms[u]<ms[G]) G=u; 66 } 67 int que[N1],hd,tl; 68 ll dis[N1]; 69 struct node{int id;ll sum;}; 70 vector<node>rm[N1],rf[N1]; 71 int cmp(node x,node y){return a[x.id]<a[y.id];} 72 void bfs_add(int u,int g) 73 { 74 int j,v; hd=tl=1; que[hd]=u; fr[u]=0; dis[u]=0; 75 while(hd<=tl) 76 { 77 u=que[hd++]; rm[g].push_back((node){u,dis[u]}); 78 for(j=e.head[u];j;j=e.nxt[j]) 79 { 80 v=e.to[j]; if(use[v]||v==fr[u]) continue; 81 fr[v]=u; dis[v]=dis[u]+e.val[j]; 82 que[++tl]=v; 83 } 84 } 85 sort(rm[g].begin(),rm[g].end(),cmp); 86 for(j=1;j<rm[g].size();j++) 87 rm[g][j].sum+=rm[g][j-1].sum; 88 } 89 void bfs_sub(int u,int g) 90 { 91 int j,v; hd=tl=1; que[hd]=u; 92 while(hd<=tl) 93 { 94 u=que[hd++]; rf[g].push_back((node){u,dis[u]}); 95 for(j=e.head[u];j;j=e.nxt[j]) 96 { 97 v=e.to[j]; if(use[v]||v==fr[u]) continue; 98 que[++tl]=v; 99 } 100 } 101 sort(rf[g].begin(),rf[g].end(),cmp); 102 for(j=1;j<rf[g].size();j++) 103 rf[g][j].sum+=rf[g][j-1].sum; 104 } 105 void main_dfs(int u) 106 { 107 use[u]=1; bfs_add(u,u); 108 for(int j=e.head[u];j;j=e.nxt[j]) 109 { 110 int v=e.to[j]; if(use[v]) continue; 111 G=0; tsz=sz[v]; gra(v,-1); bfs_sub(v,G); fa[G]=u; 112 main_dfs(G); 113 } 114 } 115 using tr::Dis; 116 ll calc(vector<node>&s,int lim,int &sum,int type) 117 { 118 int l=0,r=s.size()-1,mid,ans=-1; 119 while(l<=r) 120 { 121 mid=(l+r)>>1; 122 if(a[s[mid].id]<=lim) l=mid+1,ans=mid; 123 else r=mid-1; 124 } 125 if(ans==-1) return 0; 126 sum+=type*(ans+1); 127 return s[ans].sum; 128 } 129 ll solve(int x,int L,int R) 130 { 131 ll ans=0;int sum; 132 for(int i=x;i;i=fa[i]) 133 { 134 sum=0; 135 ans+=calc(rm[i],R,sum,1)-calc(rm[i],L-1,sum,-1); 136 ans+=sum*Dis(x,i); 137 if(!fa[i]) continue; 138 sum=0; 139 ans-=calc(rf[i],R,sum,1)-calc(rf[i],L-1,sum,-1); 140 ans-=sum*Dis(x,fa[i]); 141 } 142 return ans; 143 } 144 145 int main() 146 { 147 scanf("%d%d%d",&n,&m,&ma); 148 int i,j,x,y,w,A,B,l,r;ll ans=0; 149 for(i=1;i<=n;i++) a[i]=gint(); 150 for(i=1;i<n;i++) x=gint(), y=gint(), w=gint(), e.ae(x,y,w), e.ae(y,x,w); 151 tr::init(); 152 tsz=ms[0]=n; G=0; gra(1,-1); gra(G,-1); 153 main_dfs(G); 154 for(j=1;j<=m;j++) 155 { 156 x=gint(); A=gint(); B=gint(); 157 l=(ans+A)%ma; r=(ans+B)%ma; if(l>r) swap(l,r); 158 ans=solve(x,l,r); 159 printf("%lld\n",ans); 160 } 161 return 0; 162 }