• [LNOI2014]LCA 树链剖分 离线 前缀和 思维题


    题目描述:
    给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求
    $sum_{lleq ileq r} dep[LCA(i,z)]$

    题解:

    $1$. 这个问题看起来很麻烦,我们不难发现 $dep[LCA(i,z)]geq dep[z]$,这是显然的。
    $2$. 而我们还会发现我们要求的结果可以转化为将 $z$ 到根节点的边权全部置为 1,$l<=i<=r$ 中每个点到根节点的路径和。
    $3$. 下一步,我们有不难看出这个操作是可逆的。即我们可以将 $lleq ileq r$ 中所有点到根节点之间的边权都 $+1$,求$z$到根节点的路径和。
    $4$. 还可以看出,对于同一个 $t$,答案可以转化为 $ans(1,r)-ans(1,l-1)$。

    综上,我们可以将每个询问拆成2个询问(分别询问 $l-1$ 和 $r$),并按照下标进行排序。
    一边更新一边进行查询即可。

    Code:

    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<iostream>
    #include<cstring>
    using namespace std;
    void setIO(string a){
    	freopen((a+".in").c_str(),"r",stdin);
    }
    const int maxn=200000;
    const int mod=201314;
    int n,q;
    int dep[maxn],top[maxn],son[maxn],A[maxn],fa[maxn];
    struct Get_Tree{
    	int cnt,cnt2;
    	int nex[maxn],to[maxn],head[maxn],siz[maxn];
    	void add_edge(int u,int v){
    		nex[++cnt]=head[u];
    		head[u]=cnt;
    		to[cnt]=v;
    	}
    	void dfs1(int u,int depth){
    		dep[u]=depth;
    		siz[u]=1;
    		for(int v=head[u];v;v=nex[v]){
    			dfs1(to[v],depth+1);
    			siz[u]+=siz[to[v]];
    			if(!son[u]||siz[to[v]]>siz[son[u]]) son[u]=to[v];
    		}
    	}
    	void dfs2(int u,int tp){
            top[u]=tp;
            A[u]=++cnt2;
            if(son[u])dfs2(son[u],tp);
            for(int v=head[u];v;v=nex[v])
                if(to[v]!=son[u])dfs2(to[v],to[v]);
        }
        void solve(){
        	dfs1(1,1);
        	dfs2(1,1);
        }
    }tree;
    struct Segment_Tree{
    	#define lson (o<<1)
    	#define rson (o<<1)|1
    	int sumv[maxn<<2],lazy[maxn<<2];
    	void pushdown(int l,int r,int o){
    		if(lazy[o]){
    			int mid=(l+r)>>1;
    			sumv[lson]+=(mid-l+1)*lazy[o];
    			sumv[rson]+=(r-mid)*lazy[o];
    			lazy[lson]+=lazy[o];
    			lazy[rson]+=lazy[o];
    			sumv[lson]%=mod;
    			sumv[rson]%=mod;
    			lazy[lson]%=mod;
    			lazy[rson]%=mod;
    			lazy[o]=0;
    		}
    	}
    	void pushup(int o){
    		sumv[o]=sumv[lson]+sumv[rson];
    	}
    	void update(int l,int r,int L,int R,int k,int o){
    		if(l>r||l>R||r<L)return;
    		if(l>=L && r<=R){
    			sumv[o]+=(r-l+1)*k;
    			lazy[o]+=k;
    			sumv[o]%=mod;
    			lazy[o]%=mod;
    			return;
    		}
    		int mid=(l+r)>>1;
    		pushdown(l,r,o);
    		update(l,mid,L,R,k,lson);
    		update(mid+1,r,L,R,k,rson);
    		pushup(o);
    	}
    	int query(int l,int r,int L,int R,int o){
    		if(l>r||l>R||r<L)return 0;
    		if(l>=L&&r<=R) return sumv[o];
    		int mid=(l+r)>>1;
    		pushdown(l,r,o);
    		return (long long)(query(l,mid,L,R,lson)+query(mid+1,r,L,R,rson))%mod;
    	}
    	int look_up(int x){
    		int val=0;
    		while(x){
    			val+=query(1,n,A[top[x]],A[x],1);
    			val%=mod;
    			x=fa[top[x]];
    		}
    		return val;
    	}
    	void modify(int x){
    		while(x){
    			update(1,n,A[top[x]],A[x],1,1);
    			x=fa[top[x]];
    		}
    	}
    }T;
    struct Ask{
    	int pos,idx,node,o;
    	Ask(int pos=0,int idx=0,int node=0,int o=0):pos(pos),idx(idx),node(node),o(o){}
    }ask[maxn];
    int asks=0;
    void Read(){
    	int f;
    	scanf("%d%d",&n,&q);
    	for(int i=2;i<=n;++i){
    		scanf("%d",&f);
    		fa[i]=f+1;
    		tree.add_edge(f+1,i);
    	}
    	for(int i=1;i<=q;++i){
    		int l,r,z;
    		scanf("%d%d%d",&l,&r,&z);
    		ask[++asks]=Ask(l-1+1,i,z+1,-1);
    		ask[++asks]=Ask(r+1,i,z+1,1);
    	}
    }
    int fin[maxn];
    bool cmp(Ask i,Ask j){
    	return i.pos<j.pos;
    }
    void solve(){
    	tree.solve();
    	sort(ask+1,ask+1+asks,cmp);
    	int cur=0;
    	for(int i=1;i<=asks;++i){
    		while(cur<ask[i].pos){
    			T.modify(cur+1);
    			cur+=1;
    		}
    		fin[ask[i].idx]+=T.look_up(ask[i].node)*ask[i].o;
    	}	
    	for(int i=1;i<=q;++i)printf("%d
    ",(fin[i]%mod+mod)%mod);
    }
    
    int main(){
    	Read();
    	solve();
    	return 0;
    }
    

      

  • 相关阅读:
    树世界
    清空 NumericUpDown
    没有评论的日子
    GetData.cs

    Hashtable 在程序中控制重复项
    Convert.ToInt32() VS System.Int32.Parse()
    饮食九要素
    添加 or 修改 的一个处理方式
    一个关于 电话号码 的正则表达式
  • 原文地址:https://www.cnblogs.com/guangheli/p/9879059.html
Copyright © 2020-2023  润新知