loj 139 树链剖分

题目大意:

给定一棵n个节点的树,初始时该树的根为1号节点,每个节点有一个给定的权值。下面依次进行m个操作,操作分为如下五种类型:

  • 换根:将一个指定的节点设置为树的新根
  • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值
  • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值
  • 询问路径:询问某条路径上节点的权值和
  • 询问子树:询问某个子树内节点的权值和

思路:

莫得思路

换根就完事了(讨论一下根是否在查询点的子树里)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<vector>
  8 #include<queue>
  9 #define inf 2147483648
 10 #define ll long long
 11 #define MAXN 100100
 12 using namespace std;
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
 17     while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();}
 18     return x*f;
 19 }
 20 int n,m,cnt,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1];
 21 int dep[MAXN],sz[MAXN],hsh[MAXN],HSH[MAXN],fa[MAXN],bl[MAXN],rt=1;
 22 ll tag[MAXN<<2],sum[MAXN<<2],val[MAXN];
 23 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
 24 void dfs(int x)
 25 {
 26     for(register int i=fst[x];i;i=nxt[i])
 27         if(to[i]!=fa[x]) {dep[to[i]]=dep[x]+1,fa[to[i]]=x;dfs(to[i]);sz[x]+=sz[to[i]];}
 28     sz[x]++;
 29 }
 30 void dfs(int x,int anc)
 31 {
 32     hsh[x]=++cnt,HSH[cnt]=x,bl[x]=anc;int hvs=0;
 33     for(register int i=fst[x];i;i=nxt[i])
 34         if(to[i]!=fa[x]&&sz[to[i]]>sz[hvs]) hvs=to[i];
 35     if(!hvs) return ;dfs(hvs,anc);
 36     for(register int i=fst[x];i;i=nxt[i])
 37         if(to[i]!=fa[x]&&to[i]!=hvs) dfs(to[i],to[i]);
 38 }
 39 void pshd(int k,int l,int r,int mid)
 40 {
 41     sum[k<<1]+=tag[k]*(mid-l+1),sum[k<<1|1]+=tag[k]*(r-mid);
 42     tag[k<<1]+=tag[k],tag[k<<1|1]+=tag[k],tag[k]=0;
 43 }
 44 void mdf(int k,int l,int r,int a,int b,int x)
 45 {
 46     if(l==a&&r==b) {sum[k]+=(ll)x*(r-l+1),tag[k]+=x;return ;}
 47     int mid=l+r>>1;
 48     if(tag[k]) pshd(k,l,r,mid);
 49     if(b<=mid) mdf(k<<1,l,mid,a,b,x);
 50     else if(a>mid) mdf(k<<1|1,mid+1,r,a,b,x);
 51     else {mdf(k<<1,l,mid,a,mid,x);mdf(k<<1|1,mid+1,r,mid+1,b,x);}
 52     sum[k]=sum[k<<1]+sum[k<<1|1];
 53 }
 54 ll query(int k,int l,int r,int a,int b)
 55 {
 56     if(l==a&&r==b) return sum[k];
 57     int mid=l+r>>1;
 58     if(tag[k]) pshd(k,l,r,mid);
 59     if(b<=mid) return query(k<<1,l,mid,a,b);
 60     else if(a>mid) return query(k<<1|1,mid+1,r,a,b);
 61     else return query(k<<1,l,mid,a,mid)+query(k<<1|1,mid+1,r,mid+1,b);
 62 }
 63 inline void workm()
 64 {
 65     int x=read(),c=read();
 66     if(x==rt) {mdf(1,1,n,1,n,c);return ;}ll f,res=0;int y=rt;
 67     if(hsh[x]+sz[x]-1>=hsh[rt]&&hsh[x]<=hsh[rt])
 68     {
 69         while(fa[bl[y]]!=x&&bl[y]!=bl[x]) y=fa[bl[y]];
 70         if(bl[y]==bl[x]) f=hsh[x]+1;else f=hsh[bl[y]];
 71         mdf(1,1,n,1,f-1,c);
 72         if(f+sz[HSH[f]]<=n) mdf(1,1,n,f+sz[HSH[f]],n,c);
 73     }
 74     else mdf(1,1,n,hsh[x],hsh[x]+sz[x]-1,c);
 75 }
 76 inline ll workq(int x)
 77 {
 78     if(x==rt) return sum[1];ll f,res=0;int y=rt;
 79     if(hsh[x]+sz[x]-1>=hsh[rt]&&hsh[x]<=hsh[rt])
 80     {
 81         while(fa[bl[y]]!=x&&bl[y]!=bl[x]) y=fa[bl[y]];
 82         if(bl[y]==bl[x]) f=hsh[x]+1;else f=hsh[bl[y]];
 83         res+=query(1,1,n,1,f-1);
 84         if(f+sz[HSH[f]]<=n) res+=query(1,1,n,f+sz[HSH[f]],n);
 85         return res;
 86     }
 87     else return query(1,1,n,hsh[x],hsh[x]+sz[x]-1);
 88 }
 89 int main()
 90 {
 91     n=read();int a,b,c;ll res=0;
 92     for(register int i=1;i<=n;i++) val[i]=read();
 93     for(register int i=2;i<=n;i++) {b=read();add(i,b);add(b,i);}
 94     fa[1]=1;dfs(1);cnt=0;dfs(1,1);
 95     for(register int i=1;i<=n;i++) mdf(1,1,n,hsh[i],hsh[i],val[i]);
 96     m=read();
 97     for(register int t=1;t<=m;t++)
 98     {
 99         c=read();
100         if(c==1) rt=read();
101         else if(c==2)
102         {
103             a=read(),b=read(),c=read();
104             while(bl[a]!=bl[b])
105             {
106                 if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
107                 mdf(1,1,n,hsh[bl[a]],hsh[a],c);
108                 a=fa[bl[a]];
109             }
110             if(dep[a]>dep[b]) swap(a,b);
111             mdf(1,1,n,hsh[a],hsh[b],c);
112         }
113         else if(c==4)
114         {
115             a=read(),b=read(),res=0;
116             while(bl[a]!=bl[b])
117             {
118                 if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
119                 res+=query(1,1,n,hsh[bl[a]],hsh[a]);
120                 a=fa[bl[a]];
121             }
122             if(dep[a]>dep[b]) swap(a,b);
123             res+=query(1,1,n,hsh[a],hsh[b]);
124             printf("%lld\n",res);
125         }
126         else if(c==3) workm();
127         else printf("%lld\n",workq(read()));
128     }
129 }

bzoj 3083

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/9818265.html

时间: 2024-08-13 19:15:45

loj 139 树链剖分的相关文章

LibreOJ #139 树链剖分 [树链剖分,线段树]

题目传送门 树链剖分 题目描述 这是一道模板题. 给定一棵 nnn 个节点的树,初始时该树的根为 111 号节点,每个节点有一个给定的权值.下面依次进行 mmm 个操作,操作分为如下五种类型: 换根:将一个指定的节点设置为树的新根. 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值. 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值. 询问路径:询问某条路径上节点的权值和. 询问子树:询问某个子树内节点的权值和. 输入

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with

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

树链剖分专题

学习了一下树链剖分,找了几个有意义的题目训练一下 前4题是基础训练, A.B是AOV树(点记录信息) C.D是AOE树(边记录信息) *注意一下poj好像是提交的代码包含/**/这样的注释会出问题 A.HDU 3966 题意:给你N个点M条边的一棵AOV树,有P次操作 操作分别是:‘I’:将C1到C2路径上的点增加K:     ‘D’:将C1到C2路径上的点减少K:     ‘Q’:问你C点上的权: 解:树链剖分基础题,需要注意的是杭电的服务器是windows的,代码中加入用下面这句话扩栈 #p

[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n个节点的初始颜色 下面 行每行包含两个整数x和y,表示x和y之间有一条无向边. 下面 行每行描述一个操作: “C a

bzoj1036 [ZJOI2008]树的统计Count(树链剖分)

Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条