JZOJ 4895 三部曲(线段树)
来源:互联网 发布:欧洲女装品牌 知乎 编辑:程序博客网 时间:2024/05/20 23:59
题目
因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市 被加派了k名士兵时。城市i的所有子城市需要被加派k+1名士兵。这些子城市的所有子城市需要被加派k+2名士兵。以此类推。
当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市i为根的子树中的所有城市共被加派了多少士兵。
你现在是国王的军事大臣,你能回答出国王的每个询问么?
n<=50000,q<=100000
时间限制 1s
空间限制 512M
解题思路
把树转化成一条线,每棵子树就会对应线段上一个连续的区间,再用线段树维护区间信息。这时候问题来了,区间内每个点加的值不同,怎么办呢?我们可以把k拆分成k’+dep[x],这样lazy tag就可以分别叠加了,然后把用两个线段树区间标记分别维护k’和dep[x]累加的值就可以了。
#include<cstdio>#include<cstring>#include<algorithm>#define maxn 300006#define fr(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;struct poi{ int x; poi *nex;} *a[maxn];void link(int x,int y){ poi *p=new poi; p->x=y; p->nex=a[x]; a[x]=p; return;}int i,n,q,x,y,tot,d[maxn],fa[maxn],dep[maxn],siz[maxn],pos[maxn];ll s,sum[maxn],tr[maxn*4],c1[maxn*4],c2[maxn*4];char st[4];void dfs(int x){ poi *p=new poi; siz[x]=1,d[++tot]=x,pos[x]=tot; dep[x]=dep[fa[x]]+1; for(p=a[x];p;p=p->nex) { fa[p->x]=x; dfs(p->x); siz[x]+=siz[p->x]; } return;}void update(int v,int st,int en){ int m=(st+en) >> 1; if (!c1[v] && !c2[v]) return; tr[v+v]=(tr[v+v]+c1[v]*(sum[m]-sum[st-1])+c2[v]*(m-st+1)); tr[v+v+1]=(tr[v+v+1]+c1[v]*(sum[en]-sum[m])+c2[v]*(en-m)); c1[v+v]+=c1[v],c2[v+v]+=c2[v]; c1[v+v+1]+=c1[v],c2[v+v+1]+=c2[v]; c1[v]=c2[v]=0; return;}void modify(int v,int st,int en,int l,int r,int x,int y){ if (st==l && en==r) { tr[v]+=(sum[en]-sum[st-1])+(en-st+1)*x; ++c1[v],c2[v]+=x; return; } update(v,st,en); int m=(st+en) >> 1; if (r<=m) modify(v+v,st,m,l,r,x,y); else if (l>m) modify(v+v+1,m+1,en,l,r,x,y); else { modify(v+v,st,m,l,m,x,y); modify(v+v+1,m+1,en,m+1,r,x,y); } tr[v]=tr[v+v]+tr[v+v+1]; return;}void findd(int v,int st,int en,int l,int r){ if (st==l && en==r) { s=(s+tr[v]); return; } update(v,st,en); int m=(st+en) >> 1; if (r<=m) findd(v+v,st,m,l,r); else if (l>m) findd(v+v+1,m+1,en,l,r); else { findd(v+v,st,m,l,m); findd(v+v+1,m+1,en,m+1,r); } return;}int main(){ freopen("truetears.in","r",stdin); freopen("truetears.out","w",stdout); scanf("%d%d",&n,&q); fr(i,2,n) scanf("%d",&x),link(x,i); dfs(1); fr(i,1,n) sum[i]=(sum[i-1]+dep[d[i]]); fr(i,1,q) { scanf("%s%d",st+1,&x); if (st[1]=='A') { scanf("%d",&y); int kk=y-dep[x]; modify(1,1,n,pos[x],pos[x]+siz[x]-1,kk,1); // modify2(1,1,n) } else { s=0; findd(1,1,n,pos[x],pos[x]+siz[x]-1); printf("%lld\n",s); } } return 0;}
0 0
- JZOJ 4895 三部曲(线段树)
- 【jzoj4895】【三部曲】【线段树】
- JZOJ 4920 降雷皇(最长上升子序列、线段树)
- [jzoj]3733. 【Usaco2014Open银组】照相(pairphoto) (线段树)
- [jzoj]1341. 失眠(线段树+转化不等式)
- JZOJ 4811. 排队(线段树的方法)
- jzoj 1278_排队_线段树
- jzoj 1379_【线段树】最大值_线段树
- 10.27NOIP 2016模拟赛 三部曲 树链剖分+线段树
- (jzoj snow的追寻)线段树维护树的直径
- [jzoj]1663. 【AHOI2009】维护序列(线段树+乘法加法原理)
- [jzoj]3480. 【NOIP2013模拟联考9】阿Q的停车场(park)(线段树+堆)
- jzoj 4684. 【GDOI2017模拟8.11】卡牌游戏 线段树
- jzoj 4933. 【NOIP2017提高组模拟12.24】C 线段树
- jzoj 5020. 【NOI2017模拟3.17】牛奶装瓶 线段树
- jzoj 5039. 【NOI2017模拟4.2】查询 线段树
- jzoj 5058. 【GDSOI2017模拟4.13】采蘑菇 线段树合并
- JZOJ 5232【NOIP2017模拟】带权排序(概率,线段树)
- Reiativelayout
- 线段相交模板
- oracle增加控制文件
- 11/15 日志
- cordova入门——cordova环境配置(一)
- JZOJ 4895 三部曲(线段树)
- ObjectAnimation 浅谈(一)
- 源值1.5已过时,将在未来所有版本中删除
- SpringMVC_004_HiddenHttpMethodFilter
- 无线传感网——物理层通信技术
- 网络爬虫学习笔记——网络爬虫简介
- 【模板】线段树
- 城市合伙人官网和手机版页面总结
- HTML+CSS之CSS盒模型