[NOIP模拟测试10]模板

这是道模板题

30分做法:

暴力统计,复杂度$ O(n^2) $,考场上性价比没有70分的高

70分算法:

我们发现有40分算法跟雨天的尾巴很相似,没有时间限制,直接权值线段树动态开点+启发式合并

复杂度$ O(n(log2n)^2) $,考场上我很沙雕地认为它的复杂度是$ O(n^2) $的所以没敢打,以后得多学一学复杂度分析包括内存分析了。

100分算法:

跟树链剖分的思想有些类似,首先dfs扫一边,之后以操作次数为鉴定标准求出重儿子,这个分类标准每个人的代码可能不太一样,拿我的来说这两个时间相差不大(因为我没有像某cow大神mikufun把整个子树全都扫一边)。

这个是以子树大小为标准的。

这个是以操作次数为标准的。(都好慢啊~)

继续继续~

有了重儿子之后事情就简单一些了,我们可以在dfs的时候把轻儿子的信息全部合并到自己身上,之后扫一边重儿子,

把重儿子的信息在扫的过程中塞到线段树里(下标是时间,维护贡献和体积),并且不去删除它,

然后处理当前节点这样就可以保证复杂度了。(很巧妙的运用了树剖的思想)

空间复杂度无法接受每个点都存储信息(最坏大概得三万MB),所以需要及时清空Vector

上面我粘的代码是错误的,因为我这里只是当x不是重儿子时才把重儿子的信息暴力传过去,

但是我没有考虑如果fa的祖先某一个不是重儿子,那么它的父亲就需要它的全部信息来更新线段树,而这些信息却丢失了。

改完之后过了样例开开心心地交了上去却MLE了,改成删一个添一个却又TLE!很是尴尬,

最后我想出 颓NC哥颓出 了一个巧妙的办法:

用一个数组记录某个节点的vector是谁,这样就可以避免低效地传递信息了。

再优化一下:直接把轻儿子的信息传给重儿子(当然,是在处理完重儿子答案之后)

最后我们考虑如何来跟新答案:线段树二分

二分搞满k容量的时间,之后在线段树上区间查询即可。

记得考虑k是零的情况,所以要把二分边界设为L=0,R=m,否则。。。

出题人挺良心的,只有5分是有k==0的节点。

就这样,一道模板题就被我们切啦!

复杂度$ O(n(log2n)^2) $

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<vector>
  7 #include<string>
  8 #include<cstring>
  9 #include<map>
 10 #define m(a) memset(a,0,sizeof(a))
 11 #define AA cout<<"Alita"<<endl
 12 using namespace std;
 13 const int N=1e5+10;
 14 int Q,tot,cnt,n,m,k[N],head[N],to[N*2],ne[N*2],pre[N],size[N],son[N],ans[N],id[N];
 15 vector<int>v[N],g[N];
 16 map<int,int>ma;
 17 struct tree{int l,r,w,s;}a[N*4];
 18 void add(int x,int y)
 19 {
 20         to[++tot]=y;
 21         ne[tot]=head[x];
 22         head[x]=tot;
 23 }
 24 void dfs(int x,int fa)
 25 {
 26         size[x]=1+v[x].size();
 27         for(int i=head[x];i;i=ne[i])
 28         {
 29                 int y=to[i];
 30                 if(y==fa) continue;
 31                 dfs(y,x);
 32                 size[x]+=size[y];
 33                 if(size[y]>size[son[x]]) son[x]=y;
 34         }
 35 }
 36 void build(int k,int l,int r)
 37 {
 38         a[k].l=l;
 39         a[k].r=r;
 40         if(l==r) return;
 41         int mid=(l+r)>>1;
 42         if(l<=mid) build(k<<1,l,mid);
 43         if(r>mid) build(k<<1|1,mid+1,r);
 44 }
 45 int query_size(int k,int l,int r)
 46 {
 47         if(a[k].l>=l&&a[k].r<=r) return a[k].s;
 48         int mid=(a[k].l+a[k].r)>>1,sum=0;
 49         if(l<=mid) sum+=query_size(k<<1,l,r);
 50         if(r>mid) sum+=query_size(k<<1|1,l,r);
 51         return sum;
 52 }
 53 int query_w(int k,int l,int r)
 54 {
 55         if(a[k].l>=l&&a[k].r<=r) return a[k].w;
 56         int mid=(a[k].l+a[k].r)>>1,sum=0;
 57         if(l<=mid) sum+=query_w(k<<1,l,r);
 58         if(r>mid) sum+=query_w(k<<1|1,l,r);
 59         return sum;
 60 }
 61 void Plus(int k,int val,int time,int f)
 62 {
 63         if(a[k].l==a[k].r)
 64         {
 65                 a[k].w=val;
 66                 a[k].s+=f;
 67                 return;
 68         }
 69         int mid=(a[k].l+a[k].r)>>1;
 70         if(time<=mid) Plus(k<<1,val,time,f);
 71         else Plus(k<<1|1,val,time,f);
 72         a[k].w=a[k<<1].w+a[k<<1|1].w;
 73         a[k].s=a[k<<1].s+a[k<<1|1].s;
 74 }
 75 int get(int x)
 76 {
 77         int L=0,R=m;
 78         while(L<R)
 79         {
 80                 int mid=(L+R+1)>>1;
 81                 if(query_size(1,1,mid)<=k[x]) L=mid;
 82                 else R=mid-1;
 83         }
 84         return query_w(1,1,L);
 85 }
 86 void work(int x,int fa)
 87 {
 88         for(int i=head[x];i;i=ne[i])
 89         {
 90                 int y=to[i];
 91                 if(y==fa||y==son[x]) continue;
 92                 work(y,x);
 93         }
 94         int pos=0;
 95         if(son[x]) 
 96         {
 97                 work(son[x],x);
 98                 pos=v[id[son[x]]].size();
 99                 for(int i=0;i<v[id[x]].size();i++)
100                 {
101                         v[id[son[x]]].push_back(v[id[x]][i]);
102                         g[id[son[x]]].push_back(g[id[x]][i]);
103                 }
104                 id[x]=id[son[x]];
105         }
106         for(int i=head[x];i;i=ne[i])
107         {
108                 int y=to[i];
109                 if(y==fa||y==son[x]) continue;
110                 for(int i=0;i<v[id[y]].size();i++)
111                 {
112                         v[id[x]].push_back(v[id[y]][i]);
113                         g[id[x]].push_back(g[id[y]][i]);
114                 }
115                 v[id[y]].clear();
116                 g[id[y]].clear();
117         }
118         for(int i=pos;i<v[id[x]].size();i++)
119         {
120                 if(pre[v[id[x]][i]])
121                 {
122                         if(pre[v[id[x]][i]]<g[id[x]][i]) Plus(1,0,g[id[x]][i],1);
123                         else 
124                         {
125                                 Plus(1,1,g[id[x]][i],1);
126                                 Plus(1,0,pre[v[id[x]][i]],0);
127                                 pre[v[id[x]][i]]=g[id[x]][i];
128                         }
129                 }
130                 else 
131                 {
132                         Plus(1,1,g[id[x]][i],1);
133                         pre[v[id[x]][i]]=g[id[x]][i];
134                 }
135         }
136         ans[x]=get(x);
137         if(son[fa]!=x)
138         {
139                 for(int i=0;i<v[id[x]].size();i++)
140                 {
141                         pre[v[id[x]][i]]=0;
142                         Plus(1,0,g[id[x]][i],-1);
143                 }
144         }
145 }
146 int main()
147 {
148         //freopen("1.in","r",stdin);
149         //freopen("1.out","w",stdout);
150         scanf("%d",&n);
151         for(int i=1,x,y;i<n;i++)
152         {
153                 scanf("%d%d",&x,&y);
154                 add(x,y); add(y,x);
155         }
156         for(int i=1;i<=n;i++) 
157         {
158                 id[i]=i;
159                 scanf("%d",&k[i]);
160         }
161         scanf("%d",&m);
162         build(1,1,m);
163         for(int i=1,x,y;i<=m;i++)
164         {
165                 scanf("%d%d",&x,&y);
166                 if(!ma[y]) ma[y]=++cnt;
167                 v[id[x]].push_back(ma[y]);
168                 g[id[x]].push_back(i);
169         }
170         dfs(1,0);
171         work(1,0);
172         scanf("%d",&Q);
173         for(int i=1,x;i<=Q;i++)
174         {
175                 scanf("%d",&x);
176                 printf("%d\n",ans[x]);
177         }
178         return 0;
179 }

 

posted @ 2019-07-30 14:54  ATHOSD  阅读(121)  评论(0编辑  收藏  举报