标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增ios
Time Limit: 20 Sec
Memory Limit: 512 MBc++
Descriptionpost
世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各类各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树可以生生不息、持续运转的根本基石。
世界树的形态能够用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证链接的方式会造成一棵树结构,即全部的聚居地之间能够互相到达,而且不会出现环。定义两个聚居地之间的距离为链接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,由于每条道路长度为1并且又不可能出现环,所卧a与c之间的距离为2。
出于对公平的考虑,第i年,世界树的国王须要受权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),若是距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(若是有多个临时议事处到该聚居地的距离同样,则y为其中编号最小的临时议事处)。
如今国王想知道,在q年的时间里,每年完成受权后,当年每一个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 如今这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。spa
Inputcode
第一行为一个正整数n,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
向道路。接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年受权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被受权为临时议事处的聚居地编号(保证互不相同)。ip
Outputget
输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被受权的聚居地h[j]的临时议事处管理的种族个数。数学
Sample Inputstring
10it
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8
Sample Output
1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1
HINT
N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000
虚树,竟然到如今才搞,真的太弱了,参考神牛http://lazycal.logdown.com/posts/202331-bzoj3572
orz
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<queue> using namespace std; #define LL long long #define MP(a,b) make_pair(a,b) #define PA pair<int,int> int read() { int s=0,f=1;char ch=getchar(); while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } const int N=300005; int n,m; int be[N],bn[N*2],bv[N*2],bl[N*2],bw=1; void put(int u,int v,int l) {bw++;bn[bw]=be[u];be[u]=bw;bv[bw]=v;bl[bw]=l;} int dep[N],dep2[N],siz[N]; int dfn[N],rank[N],dtot; int fa[N][19]; int h[N],t[N],tot; void dfs(int x) { dfn[rank[x]=++dtot]=x; siz[x]=1; for(int i=be[x],v;i;i=bn[i]) if(!siz[v=bv[i]]) {fa[v][0]=x; for(int j=0;fa[v][j+1]=fa[fa[v][j]][j];j++); dep[v]=dep[x]+bl[i]; dep2[v]=dep[x]+1; dfs(v); siz[x]+=siz[v]; } } int lca(int a,int b) { if(dep2[a]<dep2[b])swap(a,b); for(int i=18;i>=0;i--) if(dep2[fa[a][i]]>=dep2[b]) a=fa[a][i]; for(int i=18;i>=0;i--) if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i]; return a==b?a:fa[a][0]; } int jump(int x,int dis) { for(int i=18;i>=0;i--) if(dep[fa[x][i]]>dis) x=fa[x][i]; return x; } bool cmp(int a,int b) { return rank[a]<rank[b]; } int sta[N],top; int father[N],ans[N],val[N],hh[N]; PA md[N]; int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); n=read(); for(int i=1;i<n;i++) {int u=read(),v=read(); put(u,v,1); put(v,u,1); } dep[0]=dep2[0]=-1; dfs(1); for(int Q=read();Q--;) {m=read();tot=0; for(int i=1;i<=m;i++) {hh[i]=h[i]=read(), md[h[i]]=MP(0,h[i]); t[++tot]=h[i]; ans[h[i]]=0; } sort(&h[1],&h[m+1],cmp); top=0; for(int i=1;i<=m;i++) {int now=h[i]; if(!top){father[sta[++top]=now]=0;continue;} int LCA=lca(sta[top],now); for(;dep[sta[top]]>dep[LCA];top--) if(dep[sta[top-1]]<=dep[LCA]) father[sta[top]]=LCA; if(sta[top]!=LCA) {t[++tot]=LCA; father[LCA]=sta[top]; md[LCA]=MP(0x3f3f3f3f,0); sta[++top]=LCA; } father[now]=sta[top]; sta[++top]=now; } for(int i=1;i<=tot;i++)val[t[i]]=siz[t[i]]; sort(&t[1],&t[tot+1],cmp); for(int i=tot;i>1;i--) {int x=t[i],f=father[x]; md[f]=min(md[f],MP(dep[x]-dep[f]+md[x].first,md[x].second)); } for(int i=2;i<=tot;i++) {int x=t[i],f=father[x]; md[x]=min(md[x],MP(dep[x]-dep[f]+md[f].first,md[f].second)); } for(int i=1;i<=tot;i++) {int x=t[i],f=father[x]; if(i==1) {ans[md[x].second]+=n-siz[x]; continue; } int u=jump(x,dep[f]); val[f]-=siz[u]; if(md[f].second==md[x].second) {ans[md[f].second]+=siz[u]-siz[x]; continue; } int mid=jump(x,(md[x].first-md[f].first+dep[x]+dep[f]-(md[x].second<md[f].second))/2); ans[md[f].second]+=siz[u]-siz[mid]; ans[md[x].second]+=siz[mid]-siz[x]; } for(int i=1;i<=tot;i++) ans[md[t[i]].second]+=val[t[i]]; for(int i=1;i<=m;i++) printf("%d ",ans[hh[i]]);printf("\n"); } //fclose(stdin); //fclose(stdout); return 0; }