洛谷 P4211 [LNOI2014]LCA(树剖+线段树,差分)
作者:互联网
传送门
解题思路
调了一晚上。。紫题果然不是我现在能做的。。
首先考虑如何把多个deep的和转化成可以快速求出来的东西:
我们可以对于每个[l,r],把每个点到根节点的路径上的点权++(初始为0),这样对于每个询问(l,r,z),答案即为z到根节点的路径上的点权和。-----操作1
但是对于每个询问都操作一遍很显然会tle,所以再利用差分思想,把(l,r,z)转化为(1,r,z)-(1,l-1,z),具体来说,就是每次操作完后不清空点权,对询问进行排序,然后根据点编号从小到大依次进行操作1,并保存答案。
这样最多只会进行n次操作1。
具体如何实现操作1?
对于像这样路径上的区间加、区间求和操作,可以方便的使用树剖+线段树维护。
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=(5e4+5)*4;
const int mod=201314;
struct node{
int v,next;
}e[maxn];
struct Node{
int r,z,v,id;
}q[maxn];
int n,m,lazy[maxn],p[maxn],ans[maxn],cnt,num,deep[maxn],siz[maxn],son[maxn];
int tp[maxn],dfn[maxn],f[maxn],rk[maxn],sum[maxn];
bool cmp(Node a,Node b){
return a.r<b.r;
}
void insert(int u,int v){
cnt++;
e[cnt].v=v;
e[cnt].next=p[u];
p[u]=cnt;
}
void dfs1(int u,int dep){
deep[u]=dep;
siz[u]=1;
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
dfs1(v,dep+1);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int top){
tp[u]=top;
dfn[u]=++num;
rk[num]=u;
if(!son[u]) return;
dfs2(son[u],top);
for(int i=p[u];i!=-1;i=e[i].next){
if(e[i].v==son[u]) continue;
dfs2(e[i].v,e[i].v);
}
}
inline void pushdown(int id,int l,int r){
if(lazy[id]){
int mid=(l+r)/2;
sum[id*2]+=lazy[id]*(mid-l+1);
sum[id*2+1]+=lazy[id]*(r-mid);
lazy[id*2]+=lazy[id];
lazy[id*2+1]+=lazy[id];
lazy[id]=0;
}
}
inline void pushup(int id){
sum[id]=sum[id*2]+sum[id*2+1];
}
void update(int id,int l,int r,int x,int y){
if(x<=l&&r<=y){
lazy[id]++;
sum[id]+=(r-l+1);
return;
}
int mid=(l+r)/2;
pushdown(id,l,r);
if(x<=mid) update(id*2,l,mid,x,y);
if(y>mid) update(id*2+1,mid+1,r,x,y);
pushup(id);
}
int query(int id,int l,int r,int x,int y){
if(x<=l&&r<=y){
return sum[id]%mod;
}
int mid=(l+r)/2,res=0;
pushdown(id,l,r);
if(x<=mid) res+=query(id*2,l,mid,x,y);
if(y>mid) res+=query(id*2+1,mid+1,r,x,y);
return res%mod;
}
void add(int x){
while(tp[x]!=1){
update(1,1,n,dfn[tp[x]],dfn[x]);
x=f[tp[x]];
}
update(1,1,n,1,dfn[x]);
}
int getans(int x){
int res=0;
while(tp[x]!=1){
res=(res+query(1,1,n,dfn[tp[x]],dfn[x]))%mod;
x=f[tp[x]];
}
res+=query(1,1,n,1,dfn[x]);
return res%mod;
}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
cin>>n>>m;
f[1]=1;
for(int i=2;i<=n;i++){
cin>>f[i];
f[i]++;
insert(f[i],i);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=m;i++){
int l,r,z;
cin>>l>>r>>z;
l++;
r++;
z++;
q[i].r=l-1;
q[i].z=z;
q[i].v=-1;
q[i].id=i;
q[i+m].r=r;
q[i+m].z=z;
q[i+m].v=1;
q[i+m].id=i;
}
sort(q+1,q+2*m+1,cmp);
int now=1;
for(int i=1;i<=2*m;i++){
while(q[i].r==0) i++;
while(now<=n&&now<=q[i].r){
add(now);
now++;
}
ans[q[i].id]+=q[i].v*getans(q[i].z);
}
for(int i=1;i<=m;i++) cout<<(ans[i]%mod+mod)%mod<<endl;
return 0;
}
标签:lazy,洛谷,树剖,int,LNOI2014,tp,dfn,maxn,id 来源: https://www.cnblogs.com/yinyuqin/p/15303048.html