标签:sizeof anti ret 使用 cto 计蒜客 add nan 树状数组
18年沈阳网赛的题,一直想补但一直鸽着,终于还是补上了
一棵树,点带权,支持两种操作:
1.深度d上的权值加上x
2.询问子树u下的权值和
对每个深度按结点数量分类,结点数小于$sqrt(n)$的为1类,其余的为2类
对于1类深度,修改时暴力修改每个结点的值,查询时用树状数组
对于2类深度,修改时直接在该深度上打上标记,查询时暴力枚举该结点子树下的每个深度超过$sqrt(n)$的结点
总复杂度$O((n+q)sqrt(n))$
其实这道题本质上是一个二维平面上的区间修改查询问题,理论上利用树套树可以将复杂度降至$O((n+q)log^2n)$,但由于题目内存限制得太死所以没法使用(我没试过,有兴趣的话可以试试)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll N=1e5+10,mod=1e9+7,inf=0x3f3f3f3f; 5 ll n,Q,hd[N],ne,bg[N],ed[N],c[N],tot,cnt[N],sqrtn,sum[N]; 6 unordered_map<ll,ll> mp[N]; 7 vector<ll> vec[N]; 8 struct E {ll v,nxt;} e[N]; 9 ll lb(ll x) {return x&-x;} 10 ll get(ll u) {ll ret=0; for(; u; u-=lb(u))ret+=c[u]; return ret;} 11 void add(ll u,ll x) {for(; u<=tot; u+=lb(u))c[u]+=x;} 12 void link(ll u,ll v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 13 void dfs1(ll u,ll d=0) { 14 bg[u]=++tot,cnt[d]++; 15 for(ll i=hd[u]; ~i; i=e[i].nxt) { 16 ll v=e[i].v; 17 dfs1(v,d+1); 18 } 19 ed[u]=tot; 20 } 21 void dfs2(ll u,ll d=0) { 22 if(cnt[d]<sqrtn)vec[d].push_back(u); 23 else mp[u][d]=1; 24 for(ll i=hd[u]; ~i; i=e[i].nxt) { 25 ll v=e[i].v; 26 dfs2(v,d+1); 27 for(auto x:mp[v])mp[u][x.first]+=x.second; 28 } 29 } 30 ll qry(ll u) { 31 ll ret=get(ed[u])-get(bg[u]-1); 32 for(auto x:mp[u])ret+=sum[x.first]*x.second; 33 return ret; 34 } 35 int main() { 36 memset(hd,-1,sizeof hd),ne=tot=0; 37 scanf("%lld%lld",&n,&Q),sqrtn=sqrt(n+0.5); 38 for(ll i=1; i<n; ++i) { 39 ll u,v; 40 scanf("%lld%lld",&u,&v); 41 link(u,v); 42 } 43 dfs1(1),dfs2(1); 44 while(Q--) { 45 ll f,a,b; 46 scanf("%lld",&f); 47 if(f==1) { 48 scanf("%lld%lld",&a,&b); 49 if(cnt[a]<sqrtn)for(ll x:vec[a])add(bg[x],b); 50 else sum[a]+=b; 51 } else scanf("%lld",&a),printf("%lld\n",qry(a)); 52 } 53 return 0; 54 }
计蒜客 - A1998 Ka Chang (分块+树状数组)
标签:sizeof anti ret 使用 cto 计蒜客 add nan 树状数组
原文地址:https://www.cnblogs.com/asdfsag/p/12392124.html