[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 }