码迷,mamicode.com
首页 > 其他好文 > 详细

cf 588E Duff in the Army 树上倍增

时间:2018-02-22 21:31:42      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:dal   inf   顺序   问题   cstring   编号   str   merge   while   

题意概述:

给出一棵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])的特判就可以做到不重不漏统计(之前都是用来求最值之类的所以没有注意到这个问题)。

然后还有为什么倍增数组第二维开成17省省空间在100000的时候wa了有哪位dalao可以告诉我。。。。

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

 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][18],info[maxn][18][11],sz[maxn][18];
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) c[l++]=a[i]<b[j]?a[i++]:b[j++];
43     while(i<l1) c[l++]=a[i++];
44     while(j<l2) c[l++]=b[j++];
45     return min(l,10);
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,z,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     freopen("test.in","r",stdin);
94     freopen("test.out","w",stdout);
95     data_in();
96     work();
97     return 0;
98 }

 

cf 588E Duff in the Army 树上倍增

标签:dal   inf   顺序   问题   cstring   编号   str   merge   while   

原文地址:https://www.cnblogs.com/KKKorange/p/8459945.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!