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

[CodeChef-LVGFT]Lovers Gift

时间:2018-04-23 11:06:04      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:include   选择   getch   turn   合并   algo   答案   return   disjoint   

题目大意:
  给定一个$n(n\le10^5)$个结点的树,初始全为白点。$m(m\le10^5)$次操作,每次将点$x$染成黑色或询问从$x$出发至少经过一个黑点能到达的点中,编号次大的点。

思路:
  将操作倒序处理,即原操作变为擦除颜色和询问两种操作。用并查集维护白点连通块和若干单独的黑点。记录每个连通块或黑点出发至少经过一个黑点能到达的点中,能到达的最大和次大的点。擦除黑点时进行合并即可。维护最大、次大点时选择答案较小的连通块暴力递减。递减次数加起来是$n$。初始时每个连通块维护的最大值都是$n$,次大值都是$n-1$。而只有当连通块的点中含有$n$或$n-1$时,答案才会变小。每次合并时从两个连通块中答案比较小的往下枚举,总共最多枚举$2n$次。时间复杂度$O((n+m)\alpha(n)$比标算不知道高到哪里去了。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^0;
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^0);
 9     return x;
10 }
11 const int N=1e5+1,M=1e5+1;
12 struct Edge {
13     int to,next;
14 };
15 Edge e[N<<1];
16 int h[N],b[N],ans[N];
17 inline void add_edge(const int &u,const int &v) {
18     e[++h[0]]=(Edge){v,h[u]};h[u]=h[0];
19     e[++h[0]]=(Edge){u,h[v]};h[v]=h[0];
20 }
21 std::pair<bool,int> q[M];
22 struct DisjointSet {
23     int anc[N];
24     void reset(const int &n) {
25         for(register int i=1;i<=n;i++) anc[i]=i;
26     }
27     int find(const int &x) {
28         return x==anc[x]?x:anc[x]=find(anc[x]);
29     }
30     void merge(const int &x,const int &y) {
31         anc[find(x)]=find(y);
32     }
33     bool same(const int &x,const int &y) {
34         return find(x)==find(y);
35     }
36 };
37 DisjointSet s;
38 std::pair<int,int> max[N];
39 inline void maintain(const int &x) {
40     while(max[x].first&&s.same(x,max[x].first)) max[x].first--;
41     max[x].second=std::max(std::min(max[x].second,max[x].first-1),0);
42     while(max[x].second&&s.same(x,max[x].second)) max[x].second--;
43 }
44 int main() {
45     for(register int T=getint();T;T--) {
46         const int n=getint(),m=getint();
47         std::fill(&h[0],&h[n]+1,-1);
48         for(register int i=1;i<n;i++) {
49             add_edge(getint(),getint());
50         }
51         for(register int i=1;i<=m;i++) {
52             const bool opt=getint()&1;
53             const int x=getint();
54             if(opt&&!b[x]) b[x]=i;
55             q[i]={opt,x};
56         }
57         s.reset(n);
58         std::fill(&max[1],&max[n]+1,std::make_pair(n,n-1));
59         for(register int i=1;i<=n;i++) {
60             if(!b[i]) maintain(i);
61         }
62         for(register int x=1;x<=n;x++) {
63             if(b[x]) continue;
64             for(register int i=h[x];~i;i=e[i].next) {
65                 const int &y=e[i].to;
66                 if(b[y]||s.same(x,y)) continue;
67                 max[s.find(y)]=std::min(max[s.find(y)],max[s.find(x)]);
68                 s.merge(x,y);
69                 maintain(s.find(x));
70             }
71         }
72         for(register int i=m;i;i--) {
73             const bool opt=q[i].first;
74             const int x=q[i].second;
75             if(opt&&b[x]==i) {
76                 b[x]=0;
77                 maintain(s.find(x));
78                 for(register int i=h[x];~i;i=e[i].next) {
79                     const int &y=e[i].to;
80                     if(b[y]||s.same(x,y)) continue;
81                     max[s.find(y)]=std::min(max[s.find(y)],max[s.find(x)]);
82                     s.merge(x,y);
83                     maintain(s.find(x));
84                 }
85             }
86             if(!opt) {
87                 ans[i]=max[s.find(x)].second?:-1;
88             }
89         }
90         for(register int i=1;i<=m;i++) {
91             if(!q[i].first) printf("%d\n",ans[i]);
92         }
93     }
94     return 0;
95 }

 

[CodeChef-LVGFT]Lovers Gift

标签:include   选择   getch   turn   合并   algo   答案   return   disjoint   

原文地址:https://www.cnblogs.com/skylee03/p/8915809.html

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