bzoj 3626 [LNOI2014]LCA
题目大意
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
分析
我们考虑将z到根每个点权+1
询问l-r中每个点到根点权和,加起来,就是答案
一个点dep就是到根点权和
这是可逆的
我们可以l-r中每个点到根点权+1
再询问z
离线差分一下
注意
考前了还有这种低级错误
1.先看清题,别着急写又改来改去的,改又改得不全
2.做完题检查至少3次
细节,数组,longlong,取模等,仔仔细细的看
3.如果还是虚就对拍一下
solution
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int M=100007;
const int Q=201314;
typedef long long LL;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
}
int n,m;
int g[M],te;
struct edge{int y,next;}e[M<<1];
void addedge(int x,int y){
e[++te].y=y;e[te].next=g[x];g[x]=te;
}
int hd[M],tq;
struct query{int z,id,next;}ask[M<<1];
void addask(int x,int z,int id){
ask[++tq].z=z;ask[tq].id=id;ask[tq].next=hd[x];hd[x]=tq;
}
int dep[M],sz[M];
int son[M],pre[M];
int tid[M],pid[M];
int top[M],tdfn;
int ans[M];
struct Seg{
int sum;
int tag;
}a[M<<2];
void dfs1(int x){
sz[x]=1;
son[x]=0;
int p,y;
for(p=g[x];p;p=e[p].next)
if((y=e[p].y)!=pre[x]){
dep[y]=dep[x]+1;
pre[y]=x;
dfs1(y);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
}
void dfs2(int x){
int p,y;
tid[x]=++tdfn;
pid[tdfn]=x;
if(son[x]){
top[son[x]]=top[x];
dfs2(son[x]);
}
for(p=g[x];p;p=e[p].next)
if((y=e[p].y)!=pre[x]&&y!=son[x]){
top[y]=y;
dfs2(y);
}
}
void ins(int x,int l,int r,int tl,int tr,int d){
if(tl<=l&&r<=tr){
a[x].tag=(a[x].tag+d)%Q;
a[x].sum=(a[x].sum+((LL)d*(tr-tl+1)%Q))%Q;
return;
}
int mid=l+r>>1;
if(tr<=mid) ins(x<<1,l,mid,tl,tr,d);
else if(mid<tl) ins(x<<1|1,mid+1,r,tl,tr,d);
else ins(x<<1,l,mid,tl,mid,d),ins(x<<1|1,mid+1,r,mid+1,tr,d);
a[x].sum=(a[x].sum+((LL)d*(tr-tl+1)%Q))%Q;
}
int get(int x,int l,int r,int tl,int tr){
if(tl<=l&&r<=tr) return a[x].sum;
int mid=l+r>>1;
int res=((LL)a[x].tag*(tr-tl+1))%Q;
if(tr<=mid) res=(res+get(x<<1,l,mid,tl,tr))%Q;
else if(mid<tl) res=(res+get(x<<1|1,mid+1,r,tl,tr))%Q;
else res=(res+get(x<<1,l,mid,tl,mid)+get(x<<1|1,mid+1,r,mid+1,tr))%Q;
return res;
}
void chg(int x,int to){
for(;dep[top[x]]>=dep[to];x=pre[top[x]])
ins(1,1,n,tid[top[x]],tid[x],1);
if(dep[x]>=dep[to])
ins(1,1,n,tid[to],tid[x],1);
}
int getsum(int x,int to){
int res=0;
for(;dep[top[x]]>=dep[to];x=pre[top[x]])
res=(res+get(1,1,n,tid[top[x]],tid[x]))%Q;
if(dep[x]>=dep[to])
res=(res+get(1,1,n,tid[to],tid[x]))%Q;
return res;
}
int main(){
int p,i,x,y,z;
n=rd(),m=rd();
for(i=2;i<=n;i++){
y=rd()+1;
addedge(i,y);
addedge(y,i);
}
dep[1]=1;
pre[1]=0;
dfs1(1);
top[1]=1;
dfs2(1);
for(i=1;i<=m;i++){
x=rd()+1,y=rd()+1,z=rd()+1;
x--;
if(x) addask(x,z,-i);
addask(y,z,i);
}
for(i=1;i<=n;i++){
chg(i,1);
for(p=hd[i];p;p=ask[p].next){
x=abs(ask[p].id);
if(ask[p].id<0) ans[x]=(ans[x]-getsum(ask[p].z,1))%Q;
else ans[x]=(ans[x]+getsum(ask[p].z,1))%Q;
}
}
for(i=1;i<=m;i++) printf("%d\n",(ans[i]%Q+Q)%Q);
return 0;
}