「LuoguP3384」模板树链剖分
Posted qwerta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「LuoguP3384」模板树链剖分相关的知识,希望对你有一定的参考价值。
题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入输出格式
输入格式:第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
输入输出样例
说明
时空限制:1s,128M
数据规模:
对于30%的数据: N≤10,M≤10
对于70%的数据: N≤10^3,M≤10^3
对于100%的数据: N≤10^5,M≤10^5
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
题解
我也是会树剖的女人了!!!嗷嗷嗷嗷嗷嗷嗷嗷嗷嗷
模板题嘛QAQ,也没什么好讲的
剖了之后,对于操作1和2,在求lca的过程中做
对于操作3和4,直接在dfn[x]和dfn[x]+siz[x]-1上搞事就星了
其实操作1和2可以用树上前缀和水水水水水水(不对要随时询问好像布星QAQ)
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int MAXN=2e5+7; 5 int val[MAXN];//点权 6 //以下建原树 7 struct emm{ 8 int e,f; 9 }b[4*MAXN]; 10 int h[MAXN]; 11 int tot=0; 12 void con(int x,int y) 13 { 14 b[++tot].f=h[x]; 15 h[x]=tot; 16 b[tot].e=y; 17 b[++tot].f=h[y]; 18 h[y]=tot; 19 b[tot].e=x; 20 return; 21 } 22 //第一遍dfs 23 int d[MAXN],fa[MAXN],top[MAXN],z[MAXN],siz[MAXN]; 24 void dfs(int x) 25 { 26 siz[x]=1; 27 top[x]=x; 28 int mac=0,macc=-1; 29 for(int i=h[x];i;i=b[i].f) 30 if(!d[b[i].e]) 31 { 32 d[b[i].e]=d[x]+1; 33 fa[b[i].e]=x; 34 dfs(b[i].e); 35 siz[x]+=siz[b[i].e]; 36 if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];} 37 } 38 z[x]=mac; 39 top[mac]=x; 40 return; 41 } 42 //第二遍dfs 43 int q[MAXN],dfn[MAXN]; 44 void dfss(int x) 45 { 46 q[++tot]=x; 47 dfn[x]=tot; 48 if(z[x])dfss(z[x]); 49 for(int i=h[x];i;i=b[i].f) 50 if(fa[b[i].e]==x&&b[i].e!=z[x]) 51 dfss(b[i].e); 52 return; 53 } 54 //找top 55 int fitop(int x) 56 { 57 if(top[x]==x)return x; 58 return top[x]=fitop(top[x]); 59 } 60 //建树完成 61 int n,m,s; 62 long long mod; 63 //以下线段树 64 struct ahh{ 65 int l,r; 66 long long v,laz; 67 }a[8*MAXN]; 68 void build(int i,int ll,int rr) 69 { 70 a[i].l=ll; 71 a[i].r=rr; 72 if(ll==rr){a[i].v=val[q[ll]];return;} 73 int mid=(ll+rr)>>1; 74 build((i<<1),ll,mid); 75 build(((i<<1)|1),mid+1,rr); 76 a[i].v=a[(i<<1)].v+a[((i<<1)|1)].v%mod; 77 return; 78 } 79 void add(int i,int ll,int rr,int k) 80 { 81 if(a[i].l==ll&&a[i].r==rr) 82 {a[i].laz+=k;return;} 83 a[i].v=(long long)a[i].v+(rr-ll+1)*k%mod; 84 int mid=(a[i].l+a[i].r)>>1; 85 if(rr<=mid)add((i<<1),ll,rr,k); 86 else if(mid+1<=ll)add(((i<<1)|1),ll,rr,k); 87 else {add((i<<1),ll,mid,k);add(((i<<1)|1),mid+1,rr,k);} 88 return; 89 } 90 void pushtag(int i) 91 { 92 if(!a[i].laz)return; 93 a[i].v=(long long)a[i].v+a[i].laz*(a[i].r-a[i].l+1)%mod; 94 if(a[i].l==a[i].r){a[i].laz=0;return;} 95 a[(i<<1)].laz+=a[i].laz; 96 a[((i<<1)|1)].laz+=a[i].laz; 97 a[i].laz=0; 98 return; 99 } 100 unsigned long long ans; 101 void find(int i,int ll,int rr) 102 { 103 pushtag(i); 104 if(a[i].l==ll&&a[i].r==rr){ans=(ans+a[i].v)%mod;return;} 105 int mid=(a[i].l+a[i].r)>>1; 106 if(rr<=mid)find((i<<1),ll,rr); 107 else if(ll>=mid+1)find(((i<<1)|1),ll,rr); 108 else {find((i<<1),ll,mid);find(((i<<1)|1),mid+1,rr);} 109 return; 110 } 111 // 112 int main() 113 { 114 //freopen("a.in","r",stdin); 115 scanf("%d%d%d%lld",&n,&m,&s,&mod); 116 for(int i=1;i<=n;++i) 117 scanf("%d",&val[i]); 118 for(int i=1;i<n;++i) 119 { 120 int x,y; 121 scanf("%d%d",&x,&y); 122 con(x,y); 123 } 124 d[s]=1; 125 dfs(s); 126 tot=0; 127 dfss(s); 128 for(int i=1;i<=n;++i) 129 top[i]=fitop(i); 130 build(1,1,n); 131 //run 132 for(int c=1;c<=m;++c) 133 { 134 int opt; 135 scanf("%d",&opt); 136 if(opt==1) 137 { 138 int x,y,z; 139 scanf("%d%d%d",&x,&y,&z); 140 //lca 141 while(top[x]!=top[y]) 142 { 143 if(d[top[x]]>d[top[y]]) 144 { 145 add(1,dfn[top[x]],dfn[x],z); 146 x=fa[top[x]]; 147 } 148 else 149 { 150 add(1,dfn[top[y]],dfn[y],z); 151 y=fa[top[y]]; 152 } 153 } 154 if(d[x]>d[y])add(1,dfn[y],dfn[x],z); 155 else add(1,dfn[x],dfn[y],z); 156 } 157 else if(opt==2) 158 { 159 int x,y; 160 scanf("%d%d",&x,&y); 161 ans=0; 162 while(top[x]!=top[y]) 163 { 164 if(d[top[x]]>d[top[y]]) 165 { 166 find(1,dfn[top[x]],dfn[x]); 167 ans%=mod; 168 x=fa[top[x]]; 169 } 170 else 171 { 172 find(1,dfn[top[y]],dfn[y]); 173 ans%=mod; 174 y=fa[top[y]]; 175 } 176 } 177 if(d[x]>d[y])find(1,dfn[y],dfn[x]); 178 else find(1,dfn[x],dfn[y]); 179 printf("%lld ",ans%mod); 180 } 181 else if(opt==3) 182 { 183 int x,z; 184 scanf("%d%d",&x,&z); 185 add(1,dfn[x],dfn[x]+siz[x]-1,z); 186 } 187 else 188 { 189 int x; 190 scanf("%d",&x); 191 ans=0; 192 find(1,dfn[x],dfn[x]+siz[x]-1); 193 printf("%lld ",ans%mod); 194 } 195 } 196 return 0; 197 }
以上是关于「LuoguP3384」模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章