題目來源:NOI2019模擬測試賽(九)ios
第一眼看到題以爲這不是震波的徹底弱化版嗎……而後開開心心的碼了個點分治ide
碼到一半忽然發現看錯題了……心態崩了因而就棄療手玩提答去了測試
因而就快樂墊底了ui
最後發現這是個最毒瘤的題……改題寫+調了一天,代碼長度再次進入前五排行榜spa
(明明是在線作法爲何不強制在線呢)code
因爲是詢問樹上某些關鍵點的信息,且$\sum k$比較小,因此考慮建出虛樹處理詢問;blog
如圖,對於虛樹上一個不是關鍵點的點$u$,顯然他的最大監視半徑就是$max\{r_v-dis_{u,v}|v是u的子節點\}$;ci
這個能夠經過逆拓撲序在虛樹上一遍DP求出來;get
因爲虛樹的點數是$O(k)$的,因此能夠直接用點分治預處理離每一個點距離小於等於$r$的點數量,而後$O(logn)$處理虛樹上全部點的詢問;string
可是這樣作顯然會有點被重複計算,如圖,陰影部分的點就被計算了兩次(圖中是一條鏈,實際上可能還有其它分支也被重複計算了);
考慮被重複計算的部分有什麼性質,容易發現它實際上就是距離$u$和$v$的監視半徑重疊部分中心不超過$\frac{r_u+r_v-dis_{u,v}}{2}$的點集,顯然這也能夠當成相似的詢問用點分治處理;
對虛樹上每一對有重疊的父子都相似處理一遍,就能夠減去全部重疊部分的額外影響,所以不用額外考慮被覆蓋了三次四次甚至以上的點;
因爲虛樹的邊數=點數-1,因此這一部分的時間複雜度顯然是對的;
可是這樣還有一個小問題:如圖,若是重疊部分邊長度爲奇數,那麼是找不到中心點的;
實際上這時中心點在一條邊上,因此能夠拆邊,把樹上每條本來的邊都當作一個點,就能夠解決了;
至此這道題終於作完了……具體實現的時候並不用把虛樹真正建出來,只記錄每一個點的父節點和拓撲序便可;
總的時間複雜度$O((n+\sum k)logn)$,常數很大。
寫的時候細節超多……外面的點分治要記一萬個信息……輕鬆喜提200行+
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<cmath> 7 #include<queue> 8 #include<stack> 9 #define inf 2147483647 10 #define eps 1e-9 11 using namespace std; 12 typedef long long ll; 13 typedef double db; 14 struct edge{ 15 int v,next; 16 }a[200001]; 17 int n,m,u,v,K,S,rt,mxd,ans,tot=0,tim=0,fkfa[100001],dfn[100001],nmd[100001],head[100001],dps[100001],md1[100001],*s1[100001],md2[100001],*s2[100001],ddp[100001],dfdep[100001],dfrt[100001][20],dfds[100001][20],k[100001],r[100001],siz[100001],mx[100001],dep[100001],fa[100001][17]; 18 bool used[100001],isk[100001]; 19 stack<int>st; 20 vector<int>vec; 21 bool cmp(int a,int b){ 22 return dfn[a]<dfn[b]; 23 } 24 void add(int u,int v){ 25 a[++tot].v=v; 26 a[tot].next=head[u]; 27 head[u]=tot; 28 } 29 void dfs(int u,int ff,int dpt){ 30 dep[u]=dpt; 31 dfn[u]=++tim; 32 nmd[tim]=u; 33 fa[u][0]=ff; 34 for(int i=1;i<=16;i++)fa[u][i]=fa[fa[u][i-1]][i-1]; 35 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){ 36 int v=a[tmp].v; 37 if(v!=ff){ 38 dfs(v,u,dpt+1); 39 } 40 } 41 } 42 int lca(int u,int v){ 43 if(dep[u]<dep[v])swap(u,v); 44 int l=dep[u]-dep[v]; 45 for(int i=16;i>=0;i--){ 46 if((1<<i)&l){ 47 u=fa[u][i]; 48 } 49 } 50 if(u==v)return u; 51 for(int i=16;i>=0;i--){ 52 if(fa[u][i]!=fa[v][i]){ 53 u=fa[u][i],v=fa[v][i]; 54 } 55 } 56 return fa[u][0]; 57 } 58 int getfa(int u,int l){ 59 for(int i=16;i>=0;i--){ 60 if((1<<i)&l){ 61 u=fa[u][i]; 62 } 63 } 64 return u; 65 } 66 void dfsrt(int u,int fa){ 67 siz[u]=1; 68 mx[u]=0; 69 mxd=max(mxd,ddp[u]); 70 if(u<=n)dps[ddp[u]]++; 71 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){ 72 int v=a[tmp].v; 73 if(!used[v]&&v!=fa){ 74 dfsrt(v,u); 75 siz[u]+=siz[v]; 76 mx[u]=max(mx[u],siz[v]); 77 } 78 } 79 mx[u]=max(mx[u],S-siz[u]); 80 if(mx[u]<mx[rt])rt=u; 81 } 82 void dfsdep(int u,int fa,int ls,int dpt){ 83 siz[u]=1; 84 ddp[u]=dpt; 85 dfdep[u]++; 86 dfrt[u][dfdep[u]]=ls; 87 dfds[u][dfdep[u]]=dpt; 88 mxd=max(mxd,dpt); 89 if(u<=n)dps[dpt]++; 90 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){ 91 int v=a[tmp].v; 92 if(!used[v]&&v!=fa){ 93 dfsdep(v,u,ls,dpt+1); 94 siz[u]+=siz[v]; 95 } 96 } 97 } 98 void divide(int u){ 99 used[u]=true; 100 ddp[u]=mxd=0; 101 dfsdep(u,0,u,0); 102 md1[u]=mxd; 103 s1[u]=new int[mxd+1]; 104 for(int i=0;i<=mxd;i++){ 105 s1[u][i]=dps[i]; 106 if(i)s1[u][i]+=s1[u][i-1]; 107 dps[i]=0; 108 } 109 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){ 110 int v=a[tmp].v; 111 if(!used[v]){ 112 mxd=rt=0; 113 S=siz[v]; 114 dfsrt(v,u); 115 md2[rt]=mxd; 116 s2[rt]=new int[mxd+1]; 117 for(int i=0;i<=mxd;i++){ 118 s2[rt][i]=dps[i]; 119 if(i)s2[rt][i]+=s2[rt][i-1]; 120 dps[i]=0; 121 } 122 divide(rt); 123 } 124 } 125 } 126 void buildfaketree(){ 127 while(!st.empty())st.pop(); 128 vec.clear(); 129 sort(k+1,k+K+1,cmp); 130 st.push(k[1]); 131 for(int i=2;i<=K;i++){ 132 int z=lca(k[i],st.top()); 133 if(!isk[z])r[z]=-1; 134 while(!st.empty()&&dep[z]<dep[st.top()]){ 135 int x=st.top(); 136 st.pop(); 137 vec.push_back(x); 138 if(!st.empty()&&dep[z]<dep[st.top()])fkfa[x]=st.top(); 139 else fkfa[x]=z; 140 } 141 if(st.empty()||dep[z]>dep[st.top()])st.push(z); 142 if(k[i]!=z)st.push(k[i]); 143 } 144 while(!st.empty()){ 145 int x=st.top(); 146 st.pop(); 147 vec.push_back(x); 148 if(!st.empty())fkfa[x]=st.top(); 149 else fkfa[x]=0; 150 } 151 } 152 int getci(int u,int r){ 153 int nw,d1,d2,ret=0; 154 for(int i=dfdep[u];i;i--){ 155 nw=dfrt[u][i]; 156 d1=dfds[u][i]; 157 d2=dfds[u][i-1]; 158 if(d1<=r)ret+=s1[nw][min(r-d1,md1[nw])]; 159 if(i>1&&d2<=r)ret-=s2[nw][min(r-d2,md2[nw])]; 160 } 161 return ret; 162 } 163 void getans(){ 164 ans=0; 165 int u,ft,ds,mid,len=vec.size(); 166 for(int i=0;i<len;i++){ 167 u=vec[i]; 168 r[fkfa[u]]=max(r[fkfa[u]],r[u]-dep[u]+dep[fkfa[u]]); 169 } 170 for(int i=len-1;i>=0;i--){ 171 u=vec[i]; 172 r[u]=max(r[u],r[fkfa[u]]-dep[u]+dep[fkfa[u]]); 173 } 174 for(int i=0;i<len;i++){ 175 u=vec[i]; 176 ans+=getci(u,r[u]); 177 } 178 for(int i=0;i<len-1;i++){ 179 u=vec[i]; 180 ft=fkfa[u]; 181 ds=dep[u]-dep[ft]; 182 if(r[u]+r[ft]>=ds){ 183 mid=getfa(u,(r[u]-r[ft]+ds)/2); 184 ans-=getci(mid,r[u]-(r[u]-r[ft]+ds)/2); 185 } 186 } 187 } 188 void pt(int *s){ 189 for(int i=1;i<=n*2-1;i++)printf("%d ",s[i]); 190 puts(""); 191 } 192 int main(){ 193 memset(head,-1,sizeof(head)); 194 scanf("%d",&n); 195 for(int i=1;i<n;i++){ 196 scanf("%d%d",&u,&v); 197 add(u,n+i); 198 add(n+i,u); 199 add(v,n+i); 200 add(n+i,v); 201 } 202 dfs(1,0,0); 203 S=n*2-1; 204 mx[rt]=6666666; 205 dfsrt(1,-1); 206 memset(dps,0,sizeof(dps)); 207 divide(rt); 208 scanf("%d",&m); 209 while(m--){ 210 scanf("%d",&K); 211 r[0]=-1; 212 for(int i=1;i<=K;i++){ 213 scanf("%d",&k[i]); 214 scanf("%d",&r[k[i]]); 215 r[k[i]]*=2; 216 isk[k[i]]=true; 217 } 218 buildfaketree(); 219 for(int i=1;i<=K;i++)isk[k[i]]=false; 220 getans(); 221 printf("%d\n",ans); 222 } 223 return 0; 224 }