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)
每次询问完要将标记清空。
 #include<bits/stdc++.h>
using namespace std;
#define MOD 2147483648LL
#define MAXN 200010
#define LL long long
struct NODE
{
int begin,end,next;
}edge[MAXN*];
struct node
{
int left,right;
LL sum,tag,tag1,prey;
}tree[MAXN*];
int cnt,Head[MAXN],n,deep[MAXN],size[MAXN],P[MAXN][],pos[MAXN],belong[MAXN],ks[MAXN],js[MAXN],SIZE;
bool vis[MAXN];
void addedge(int bb,int ee)
{
edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt;
}
void addedge1(int bb,int ee)
{
addedge(bb,ee);addedge(ee,bb);
}
int read()
{
int s=,fh=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')fh=-;ch=getchar();}
while(ch>=''&&ch<=''){s=s*+(ch-'');ch=getchar();}
return s*fh;
}
void dfs1(int u)
{
int i,v;
size[u]=;vis[u]=true;
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(vis[v]==false)
{
deep[v]=deep[u]+;
P[v][]=u;
dfs1(v);
size[u]+=size[v];
}
}
}
void Ycl()
{
int i,j;
for(j=;(<<j)<=n;j++)
{
for(i=;i<=n;i++)
{
if(P[i][j-]!=-)P[i][j]=P[P[i][j-]][j-];
}
}
}
void dfs2(int u,int chain)
{
int k=,i,v;
pos[u]=++SIZE;belong[u]=chain;ks[u]=SIZE;
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(deep[v]>deep[u]&&size[v]>size[k])k=v;
}
if(k==){js[u]=SIZE;return;}
dfs2(k,chain);
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(deep[v]>deep[u]&&v!=k)dfs2(v,v);
}
js[u]=SIZE;
}
void Pushup(int k)
{
tree[k].sum=(tree[k*].sum+tree[k*+].sum)%MOD;
tree[k].prey=(tree[k*].prey+tree[k*+].prey)%MOD;
}
void Build(int k,int l,int r)
{
tree[k].left=l;tree[k].right=r;tree[k].tag=-;/*一定要赋为-1*/tree[k].tag1=0LL;tree[k].sum=0LL;
if(l==r)return;
int mid=(l+r)/;
Build(k*,l,mid);Build(k*+,mid+,r);
Pushup(k);
}
void Update(int k,int k1)
{
tree[k].tag=(LL)k1;
tree[k].prey=(tree[k].sum*(LL)k1)%MOD;
}
void Update1(int k,int k1)
{
tree[k].tag1=(tree[k].tag1+(LL)k1)%MOD;
tree[k].sum=(tree[k].sum+((LL)tree[k].right-(LL)tree[k].left+1LL)*(LL)k1)%MOD;
}
void Pushdown(int k)
{
int l=k*,r=k*+;
if(tree[k].tag1!=0LL)
{
Update1(l,tree[k].tag1);
Update1(r,tree[k].tag1);
tree[k].tag1=0LL;
}
if(tree[k].tag!=-)
{
Update(l,tree[k].tag);
Update(r,tree[k].tag);
tree[k].tag=-;
}
}
void Add(int k,int l,int r,int A)
{
if(l==tree[k].left&&tree[k].right==r){Update1(k,A);return;}
int mid=(tree[k].left+tree[k].right)/;
Pushdown(k);
if(r<=mid)Add(k*,l,r,A);
else if(l>mid)Add(k*+,l,r,A);
else {Add(k*,l,mid,A);Add(k*+,mid+,r,A);}
Pushup(k);
}
void Change(int k,int l,int r,int C)
{
if(tree[k].tag==C)return;
if(l==tree[k].left&&tree[k].right==r){Update(k,C);return;}
int mid=(tree[k].left+tree[k].right)/;
Pushdown(k);
if(r<=mid)Change(k*,l,r,C);
else if(l>mid)Change(k*+,l,r,C);
else {Change(k*,l,mid,C);Change(k*+,mid+,r,C);}
Pushup(k);
}
void Solve_change(int x,int fa,int C)
{
while(belong[x]!=belong[fa])
{
//if(deep[belong[x]]<deep[belong[fa]])swap(x,fa);
Change(,pos[belong[x]],pos[x],C);
x=P[belong[x]][];
}
//if(deep[x]<deep[fa])swap(x,fa);
Change(,pos[fa],pos[x],C);
}
int main()
{
int bb,ee,Q,i,zs,s1,s2,s3,j;
n=read();
memset(Head,-,sizeof(Head));cnt=;
for(i=;i<n;i++){bb=read();ee=read();addedge1(bb,ee);}
memset(P,-,sizeof(P));SIZE=;
dfs1();Ycl();
dfs2(,);
Q=read();
Build(,,n);
for(i=;i<=Q;i++)
{
zs=read();
if(zs==){s1=read();s2=read();Add(,ks[s1],js[s1],s2);}
else
{
s1=read();
for(j=;j<=s1;j++)
{
s2=read();s3=read();
if(deep[s2]<deep[s3])swap(s2,s3);
Solve_change(s2,s3,);
//printf("%d\n",tree[1].prey);
//Update(1,0);
}
printf("%lld\n",tree[].prey%MOD);
Update(,);
}
}
fclose(stdin);
fclose(stdout);
return ;
}

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

  1. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  2. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

  3. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  4. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  5. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

  6. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  7. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  8. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  9. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  10. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

随机推荐

  1. Reactor模式(反应器模式)

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...

  2. 关于javac编译时出现“非法字符:\65279”的解决方法

    一般用UE或记事本编辑过的UTF-8的文件头会加入BOM标识,该标识由3个char组成.在UTF-8的标准里该BOM标识是可有可无的,Sun 的javac 在编译带有BOM的UTF-8的格式的文件时会 ...

  3. MVC去掉传参时的验证:从客户端中检测到有潜在危险的Request.QueryString值

    解决方法:给Action添加属性[ValidateInput(false)]. 例: [ValidateInput(false)] public ActionResult Index(string o ...

  4. 洛谷 P1063 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

  5. @Transient注解

    以下两个包都包含@Transient注解 java.beans.Transient; javax.persistence.Transient; 使用@Transient时注意区别二者

  6. AForm — 模型驱动的自动化表单解决方案

    http://xiehuiqi220.github.io/AForm/doc/book/#

  7. oracle----修改表中的数据

    1. 修改表中的数据:UPDATE语句: 语法: UPDTAE table_name SET column1 = value1,... [WHERE conditions] (2),无条件的更新(没有 ...

  8. 让Eclipse使用新版本的JRE

    更新到新的 Mac OS X 再打开Eclipse 编译程序会报错, Exception in thread "main" java.lang.UnsupportedClassVe ...

  9. hdu 3480

    斜率dp #include<cstdio> #include<cstring> #include<algorithm> #include<queue> ...

  10. Android List去掉重复数据

    今天用数据库获取数据发现有个字段的数据重复了,于是就写了下面这个方法去除重复的数据. public static List<String> removeDuplicate(List< ...