Codeforces Round #326 Div.1 C.Duff in the Army 树上倍增

题意概述:

给出一棵N个结点的树,然后有M个居民分散在这棵树的结点上(允许某个结点没有居民)。现在给出一些询问形如u,v,a,定义k=min(x,a),其中x表示的是u->v路径上的居民数量。将所有路径上的居民编号升序排列之后得到序列p1,p2,...,px,要求对于每一组询问,输出k,p1,p2,...,pk。

N,M,Q<=10^5,1<=a<=10.

 

分析:

实际上这个题是被丢在数据结构作业里面的只是。。。。好像没有这个必要?

分析一波可以发现每个点可能在答案中出现的居民最多只有10个,所以说按照出现的顺序依次把每个点的至多10个居民储存起来,然后倍增的时候用归并排序的思想合并就可以了。时间复杂度O(10nlogn)。

实现过程中注意到一些问题,今后用倍增统计点的信息的时候都用半开半闭就好了,加上对链顶端(x=y时对x,否则x,y一起爬之后对x,y,fa[x][0])的特判就可以做到不重不漏统计(之前都是用来求最值之类的所以没有注意到这个问题)。

所以。。。数据结构是树的意思吗。。。。(感觉听了小火车讲课之后写代码的时候都在各种压长度?)

所以这个时限的4s是输入输出的锅?(实测手写0.5s的事情)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 const int maxn=100005;
14 
15 int N,M,Q;
16 struct edge{ int to,next; }E[maxn<<1];
17 int first[maxn],np,dep[maxn],fa[maxn][17],info[maxn][17][10],sz[maxn][17];
18 int ans[25],tmp[25];
19 
20 void add_edge(int u,int v)
21 {
22     E[++np]=(edge){v,first[u]};
23     first[u]=np;
24 }
25 void data_in()
26 {
27     scanf("%d%d%d",&N,&M,&Q);
28     int x,y;
29     for(int i=1;i<N;i++){
30         scanf("%d%d",&x,&y);
31         add_edge(x,y);
32         add_edge(y,x);
33     }
34     for(int i=1;i<=M;i++){
35         scanf("%d",&x);
36         if(sz[x][0]<10) info[x][0][sz[x][0]++]=i;
37     }
38 }
39 int merge(int *a,int *b,int l1,int l2,int *c)
40 {
41     int l=0,i=0,j=0;
42     while(i<l1&&j<l2&&l<10) c[l++]=a[i]<b[j]?a[i++]:b[j++];
43     while(i<l1&&l<10) c[l++]=a[i++];
44     while(j<l2&&l<10) c[l++]=b[j++];
45     return l;
46 }
47 void DFS(int i,int f,int d)
48 {
49     fa[i][0]=f,dep[i]=d;
50     for(int j=1;(1<<j)<d;j++){
51         fa[i][j]=fa[fa[i][j-1]][j-1];
52         sz[i][j]=merge(info[i][j-1],info[fa[i][j-1]][j-1],sz[i][j-1],sz[fa[i][j-1]][j-1],info[i][j]);
53     }
54     for(int p=first[i];p;p=E[p].next){
55         int j=E[p].to;
56         if(j==f) continue;
57         DFS(j,i,d+1);
58     }
59 }
60 void cc(int *n,int &l,int x,int i)
61 {
62     l=merge(n,info[x][i],l,sz[x][i],tmp);
63     for(int k=0;k<l;k++) n[k]=tmp[k];
64 }
65 void LCA(int x,int y,int *n,int &l)
66 {
67     if(dep[x]<dep[y]) swap(x,y);
68     int len=dep[x]-dep[y]; l=0;
69     for(int i=0;(1<<i)<=len;i++)
70         if((1<<i)&len){ cc(n,l,x,i); x=fa[x][i]; }
71     if(x==y){ cc(n,l,x,0); return; }
72     for(int i=16;i>=0;i--) if(fa[x][i]!=fa[y][i]){
73         cc(n,l,x,i); cc(n,l,y,i);
74         x=fa[x][i],y=fa[y][i];
75     }
76     cc(n,l,x,0); cc(n,l,y,0);
77     cc(n,l,fa[x][0],0);
78 }
79 void work()
80 {
81     DFS(1,0,1);
82     int x,y,a,l;
83     for(int i=1;i<=Q;i++){
84         scanf("%d%d%d",&x,&y,&a);
85         LCA(x,y,ans,l);
86         printf("%d ",min(a,l));
87         for(int j=0;j<min(a,l);j++) printf("%d ",ans[j]);
88         printf("\n");
89     }
90 }
91 int main()
92 {
93 data_in(); 94 work(); 95 return 0; 96 }

 

posted @ 2018-02-22 19:52  KKKorange  阅读(157)  评论(0编辑  收藏  举报