Tsinsen A1517. 动态树 树链剖分,线段树,子树操作

题目 : http://www.tsinsen.com/A1517

A1517. 动态树

时间限制:3.0s   内存限制:1.0GB

总提交次数:227   AC次数:67   平均分:49.52

将本题分享到:

查看未格式化的试题   提交   试题讨论

试题来源

  中国国家队清华集训 2013-2014 第四天

问题描述

  小明在楼下种了一棵动态树, 该树每天会在某些节点上长出一些果子. 这棵树的根节点为1, 它有n个节点, n-1条边.

  别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件

  事件0:
  这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.

  事件1:
  小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.

  初始时, 每个节点上都没有果子.

输入格式

  第一行一个整数n(1<=n<=200,000), 即节点数.
  接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
  在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
  最后nQ行, 每行开头要么是0, 要么是1.
  如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
  如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

输出格式

  对于每个事件1, 输出询问的果子数.

样例输入

5
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4

样例输出

13

数据规模和约定

  对于测试点1, 有1 <= n <= 2,000, 1 <= nQ <= 2,000, K <=5
  对于测试点{2, 3}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K = 1
  对于测试点{4, 5}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K <= 2
  对于测试点{6, 7}, 有1 <= n <= 100,000, 1 <= nQ <= 100,000, K <= 3
  对于测试点{8, 9, 10}, 有1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.
  同一组类型的数据有梯度.

  生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

提交   试题讨论

题解:

树链剖分+线段树+子树操作

修改时将链上的点打标记(注意:初始时这个标记要赋为 -1 ,不能赋为 0 ,因为 0 在之后的操作中要用。)然后查询时,将链上的标记的值相加,边加边取余。(好像可以自然溢出,因为给的数为2^31)

每次询问完要将标记清空。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define MOD 2147483648LL
  4 #define MAXN 200010
  5 #define LL long long
  6 struct NODE
  7 {
  8     int begin,end,next;
  9 }edge[MAXN*2];
 10 struct node
 11 {
 12     int left,right;
 13     LL sum,tag,tag1,prey;
 14 }tree[MAXN*4];
 15 int cnt,Head[MAXN],n,deep[MAXN],size[MAXN],P[MAXN][18],pos[MAXN],belong[MAXN],ks[MAXN],js[MAXN],SIZE;
 16 bool vis[MAXN];
 17 void addedge(int bb,int ee)
 18 {
 19     edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt;
 20 }
 21 void addedge1(int bb,int ee)
 22 {
 23     addedge(bb,ee);addedge(ee,bb);
 24 }
 25 int read()
 26 {
 27     int s=0,fh=1;char ch=getchar();
 28     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)fh=-1;ch=getchar();}
 29     while(ch>=‘0‘&&ch<=‘9‘){s=s*10+(ch-‘0‘);ch=getchar();}
 30     return s*fh;
 31 }
 32 void dfs1(int u)
 33 {
 34     int i,v;
 35     size[u]=1;vis[u]=true;
 36     for(i=Head[u];i!=-1;i=edge[i].next)
 37     {
 38         v=edge[i].end;
 39         if(vis[v]==false)
 40         {
 41             deep[v]=deep[u]+1;
 42             P[v][0]=u;
 43             dfs1(v);
 44             size[u]+=size[v];
 45         }
 46     }
 47 }
 48 void Ycl()
 49 {
 50     int i,j;
 51     for(j=1;(1<<j)<=n;j++)
 52     {
 53         for(i=1;i<=n;i++)
 54         {
 55             if(P[i][j-1]!=-1)P[i][j]=P[P[i][j-1]][j-1];
 56         }
 57     }
 58 }
 59 void dfs2(int u,int chain)
 60 {
 61     int k=0,i,v;
 62     pos[u]=++SIZE;belong[u]=chain;ks[u]=SIZE;
 63     for(i=Head[u];i!=-1;i=edge[i].next)
 64     {
 65         v=edge[i].end;
 66         if(deep[v]>deep[u]&&size[v]>size[k])k=v;
 67     }
 68     if(k==0){js[u]=SIZE;return;}
 69     dfs2(k,chain);
 70     for(i=Head[u];i!=-1;i=edge[i].next)
 71     {
 72         v=edge[i].end;
 73         if(deep[v]>deep[u]&&v!=k)dfs2(v,v);
 74     }
 75     js[u]=SIZE;
 76 }
 77 void Pushup(int k)
 78 {
 79     tree[k].sum=(tree[k*2].sum+tree[k*2+1].sum)%MOD;
 80     tree[k].prey=(tree[k*2].prey+tree[k*2+1].prey)%MOD;
 81 }
 82 void Build(int k,int l,int r)
 83 {
 84     tree[k].left=l;tree[k].right=r;tree[k].tag=-1;/*一定要赋为-1*/tree[k].tag1=0LL;tree[k].sum=0LL;
 85     if(l==r)return;
 86     int mid=(l+r)/2;
 87     Build(k*2,l,mid);Build(k*2+1,mid+1,r);
 88     Pushup(k);
 89 }
 90 void Update(int k,int k1)
 91 {
 92     tree[k].tag=(LL)k1;
 93     tree[k].prey=(tree[k].sum*(LL)k1)%MOD;
 94 }
 95 void Update1(int k,int k1)
 96 {
 97     tree[k].tag1=(tree[k].tag1+(LL)k1)%MOD;
 98     tree[k].sum=(tree[k].sum+((LL)tree[k].right-(LL)tree[k].left+1LL)*(LL)k1)%MOD;
 99 }
100 void Pushdown(int k)
101 {
102     int l=k*2,r=k*2+1;
103     if(tree[k].tag1!=0LL)
104     {
105         Update1(l,tree[k].tag1);
106         Update1(r,tree[k].tag1);
107         tree[k].tag1=0LL;
108     }
109     if(tree[k].tag!=-1)
110     {
111         Update(l,tree[k].tag);
112         Update(r,tree[k].tag);
113         tree[k].tag=-1;
114     }
115 }
116 void Add(int k,int l,int r,int A)
117 {
118     if(l==tree[k].left&&tree[k].right==r){Update1(k,A);return;}
119     int mid=(tree[k].left+tree[k].right)/2;
120     Pushdown(k);
121     if(r<=mid)Add(k*2,l,r,A);
122     else if(l>mid)Add(k*2+1,l,r,A);
123     else {Add(k*2,l,mid,A);Add(k*2+1,mid+1,r,A);}
124     Pushup(k);
125 }
126 void Change(int k,int l,int r,int C)
127 {
128     if(tree[k].tag==C)return;
129     if(l==tree[k].left&&tree[k].right==r){Update(k,C);return;}
130     int mid=(tree[k].left+tree[k].right)/2;
131     Pushdown(k);
132     if(r<=mid)Change(k*2,l,r,C);
133     else if(l>mid)Change(k*2+1,l,r,C);
134     else {Change(k*2,l,mid,C);Change(k*2+1,mid+1,r,C);}
135     Pushup(k);
136 }
137 void Solve_change(int x,int fa,int C)
138 {
139     while(belong[x]!=belong[fa])
140     {
141         //if(deep[belong[x]]<deep[belong[fa]])swap(x,fa);
142         Change(1,pos[belong[x]],pos[x],C);
143         x=P[belong[x]][0];
144     }
145     //if(deep[x]<deep[fa])swap(x,fa);
146     Change(1,pos[fa],pos[x],C);
147 }
148 int main()
149 {
150     int bb,ee,Q,i,zs,s1,s2,s3,j;
151     n=read();
152     memset(Head,-1,sizeof(Head));cnt=1;
153     for(i=1;i<n;i++){bb=read();ee=read();addedge1(bb,ee);}
154     memset(P,-1,sizeof(P));SIZE=0;
155     dfs1(1);Ycl();
156     dfs2(1,1);
157     Q=read();
158     Build(1,1,n);
159     for(i=1;i<=Q;i++)
160     {
161         zs=read();
162         if(zs==0){s1=read();s2=read();Add(1,ks[s1],js[s1],s2);}
163         else
164         {
165             s1=read();
166             for(j=1;j<=s1;j++)
167             {
168                 s2=read();s3=read();
169                 if(deep[s2]<deep[s3])swap(s2,s3);
170                 Solve_change(s2,s3,1);
171                 //printf("%d\n",tree[1].prey);
172                 //Update(1,0);
173             }
174             printf("%lld\n",tree[1].prey%MOD);
175             Update(1,0);
176         }
177     }
178     fclose(stdin);
179     fclose(stdout);
180     return 0;
181 }
时间: 2024-11-02 10:57:14

Tsinsen A1517. 动态树 树链剖分,线段树,子树操作的相关文章

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

【bzoj1959】[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航

HDU4897 (树链剖分+线段树)

Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转. 操作3:询问a->b的路径中的黑色边数量. 解题分析 考虑操作1,只需正常的树链剖分+线段树维护即可.用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量. 考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于