hdu5221 树上区间修改求所有和:树链剖分

需要注意两个地方:

1.修改整棵子树就是节点的size,因为子树映射到线段树上是连续的

2.并不是区间修改成一个值,所以预处理出子树的和,然后ok数组判断是否被占领

  1 #pragma comment(linker,"/STACK:1024000000,1024000000")
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<algorithm>
  5 #define maxn 200005
  6 #define maxm 800005
  7 using namespace std;
  8 
  9 int Now,Head[maxm],Next[maxm],Point[maxm];
 10 int num[maxn],father[maxn],deep[maxn],son[maxn];
 11 int top[maxn],tree[maxn],pre[maxn],cnt;
 12 int n,a[maxn],sumv[maxm],ok[maxm],ansv[maxm];
 13 
 14 void add(int x,int y)
 15 {
 16   Next[++Now]=Head[x];
 17   Head[x]=Now;
 18   Point[Now]=y;
 19 }
 20 //树链剖分
 21 void dfs1(int u)
 22 {
 23   num[u]=1;
 24   for (int i=Head[u];i!=-1;i=Next[i])
 25   {
 26     int v=Point[i];
 27     if (v==father[u]) continue;
 28     father[v]=u;
 29     deep[v]=deep[u]+1;
 30     dfs1(v);
 31     num[u]+=num[v];
 32     if (son[u]==-1||num[v]>num[son[u]]) son[u]=v;
 33   }
 34 }
 35 void dfs2(int u,int lead)
 36 {
 37   top[u]=lead;
 38   tree[u]=++cnt;
 39   pre[cnt]=u;
 40   if (son[u]==-1) return;
 41   dfs2(son[u],lead);
 42   for (int i=Head[u];i!=-1;i=Next[i])
 43   {
 44     int v=Point[i];
 45     if (father[u]!=v&&son[u]!=v) dfs2(v,v);
 46   }
 47 }
 48 //线段树
 49 void build(int o,int l,int r)
 50 {
 51   sumv[o]=0;
 52   if (l==r)
 53   {
 54     sumv[o]=a[pre[l]];
 55     return;
 56   }
 57   int mid=l+(r-l)/2;
 58   build(o*2,l,mid);
 59   build(o*2+1,mid+1,r);
 60   sumv[o]=sumv[o*2]+sumv[o*2+1];
 61 }
 62 void pushdown(int o)
 63 {
 64   if (ok[o])
 65   {
 66     ok[o*2]=ok[o*2+1]=1;
 67     ansv[o*2]=sumv[o*2];
 68     ansv[o*2+1]=sumv[o*2+1];
 69     ok[o]=ansv[o]=0; 
 70   }
 71 }
 72 void pushup(int o)
 73 {
 74   ansv[o]=ansv[o*2]+ansv[o*2+1];
 75   ok[o]=ok[o*2]&ok[o*2+1];
 76 }
 77 void update(int o,int l,int r,int ql,int qr,int d)
 78 {
 79   if (ql<=l&&r<=qr)
 80   {
 81     ok[o]=d;
 82     if (ok[o]) ansv[o]=sumv[o];
 83     else ansv[o]=0;
 84     return;
 85   }
 86   pushdown(o);
 87   int mid=l+(r-l)/2;
 88   if (ql<=mid) update(o*2,l,mid,ql,qr,d);
 89   if (qr>mid) update(o*2+1,mid+1,r,ql,qr,d);
 90   pushup(o);
 91 }
 92 //更改操作
 93 void change1(int l,int r)
 94 {
 95   while (top[l]!=top[r])
 96   {
 97     if (deep[top[l]]<deep[top[r]]) swap(l,r);
 98     update(1,1,n,tree[top[l]],tree[l],1);
 99     l=father[top[l]];
100   }
101   if (deep[l]>deep[r]) swap(l,r);
102   update(1,1,n,tree[l],tree[r],1);
103 }
104 void change2(int o)
105 {
106   update(1,1,n,tree[o],tree[o],0);
107 }
108 void change3(int o)
109 {
110   update(1,1,n,tree[o],tree[o]+num[o]-1,1);
111 }
112 
113 int main()
114 {
115   int T,i,x,y,q,l,r,k;
116   scanf("%d",&T);
117   while (T--)
118   {
119     scanf("%d",&n);
120     Now=0; cnt=0;
121     deep[1]=1; father[1]=0;
122     memset(son,-1,sizeof(son));
123     memset(Head,-1,sizeof(Head));
124     for (i=1;i<=n;i++) scanf("%d",&a[i]);
125     for (i=1;i<n;i++)
126     {
127       scanf("%d%d",&x,&y);
128       add(x,y); add(y,x);
129     }
130     dfs1(1); dfs2(1,1);
131     memset(ansv,0,sizeof(ansv));
132     memset(ok,0,sizeof(ok));
133     build(1,1,n);
134     scanf("%d",&q);
135     while (q--)
136     {
137       scanf("%d",&k);
138       if (k==1)
139       {
140         scanf("%d%d",&l,&r);
141         change1(l,r);
142       }
143       else if (k==2)
144       {
145         scanf("%d",&l);
146         change2(l);
147       }
148       else
149       {
150         scanf("%d",&l);
151         change3(l);
152       }
153       printf("%d\n",ansv[1]);
154     }
155   }
156   return 0;
157 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5221

转载于:https://www.cnblogs.com/xiao-xin/articles/4474839.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值