zoukankan      html  css  js  c++  java
  • [bzoj3626] [LNOI2014]LCA

    Description

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

    Input

    第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。

    Output

    输出q行,每行表示一个询问的答案。每个答案对201314取模输出

    Sample Input

    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2
    

    Sample Output

    8
    5
    

    Solution

    在线看起来就一脸不可做的样子,考虑离线怎么做。

    考虑一个转化:先给每个点定个权值,初始为0,那么(dep[lca(x,y)])可以转化成先把(1 o x)这条链每个点加上(1),然后求(1 o y)这条链的点权之和。

    然后考虑(sum_{i=l}^r dep[lca]=sum_{i=1}^rdep[lca]-sum_{i=1}^{l-1}dep[lca]),可以得到做法:

    先把一个询问拆成两个,然后按(r)为关键字(sort)一遍,然后从1到(n)枚举,链上加1,当枚举到(r)的时候,处理下所有终点为(r)的询问就好了。

    链上操作用树链剖分维护就好了,代码很好写。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    int read() {int x;read(x);return x;}
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 2e5+10;
    const int mod = 201314;
    
    int n,m,top,dfn[maxn];
    struct node{
    	int r,z,op,ans,id;
    	bool operator < (const node &rhs) const {return r<rhs.r;}
    }in[maxn];
    
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    struct Segment_Tree {
    	int tr[maxn<<2],tag[maxn<<2];
    	void update(int p) {tr[p]=tr[ls]+tr[rs];}
    	void push_tag(int p,int l,int r,int v) {tr[p]=(tr[p]+1ll*(r-l+1)*v)%mod,tag[p]=(tag[p]+v)%mod;}
    	void pushdown(int p,int l,int r) {
    		if(!tag[p]) return ;
    		push_tag(ls,l,mid,tag[p]),push_tag(rs,mid+1,r,tag[p]);
    		tag[p]=0;
    	}
    	void modify(int p,int l,int r,int x,int y) {
    		if(x<=l&&r<=y) return push_tag(p,l,r,1),void();
    		pushdown(p,l,r);
    		if(x<=mid) modify(ls,l,mid,x,y);
    		if(y>mid) modify(rs,mid+1,r,x,y);
    		update(p);
    	}
    	int query(int p,int l,int r,int x,int y) {
    		if(x<=l&&r<=y) return tr[p];
    		pushdown(p,l,r);int ans=0;
    		if(x<=mid) ans=(ans+query(ls,l,mid,x,y))%mod;
    		if(y>mid) ans=(ans+query(rs,mid+1,r,x,y))%mod;
    		return ans;
    	}
    }SGT;
    
    #undef ls
    #undef rs
    #undef mid
    
    struct Heavy_Light_Decomposition {
    	int head[maxn],sz[maxn],dfn_cnt,tot,dep[maxn],hs[maxn],fa[maxn],top[maxn];
    	struct edge{int to,nxt;}e[maxn<<1];
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    	void dfs1(int x,int f) {
    		fa[x]=f,sz[x]=1,dep[x]=dep[f]+1;
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=f) {
    				dfs1(e[i].to,x),sz[x]+=sz[e[i].to];
    				if(sz[hs[x]]<sz[e[i].to]) hs[x]=e[i].to;
    			}
    	}
    	void dfs2(int x) {
    		dfn[x]=++dfn_cnt;
    		if(hs[fa[x]]==x) top[x]=top[fa[x]];
    		else top[x]=x;
    		if(hs[x]) dfs2(hs[x]);
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=hs[x]&&e[i].to!=fa[x]) dfs2(e[i].to);
    	}
    	void modify(int x) {
    		while(x) {
    			SGT.modify(1,1,n,dfn[top[x]],dfn[x]);
    			x=fa[top[x]];
    		}
    	}
    	int query(int x) {
    		int ans=0;
    		while(x) {
    			ans=(ans+SGT.query(1,1,n,dfn[top[x]],dfn[x]))%mod;
    			x=fa[top[x]];
    		}
    		return ans;
    	}
    }HLD;
    
    int cmp(node a,node b) {return a.id<b.id;}
    
    int main() {
    	read(n),read(m);
    	for(int i=2,x;i<=n;i++) read(x),x++,HLD.ins(x,i);
    	for(int i=1;i<=m;i++) {
    		read(in[i+m].r),in[i+m].op=-1;
    		read(in[i].r),in[i].r++,in[i].op=1;
    		read(in[i].z),in[i].z++,in[i+m].z=in[i].z;
    		in[i].id=in[i+m].id=i;
    	}
    	sort(in+1,in+m*2+1);
    	HLD.dfs1(1,0),HLD.dfs2(1);
    	int p=1;
    	while(p<=m*2&&in[p].r==0) p++;
    	for(int i=1;i<=n;i++) {
    		HLD.modify(i);
    		while(p<=m*2&&in[p].r==i) in[p].ans=HLD.query(in[p].z)*in[p].op,p++;
    	}
    	sort(in+1,in+m*2+1,cmp);
    	for(int i=1;i<=m;i++) 
    		write(((in[i*2].ans+in[i*2-1].ans)%mod+mod)%mod);
    	return 0;
    }
    
    
  • 相关阅读:
    「2017 山东三轮集训 Day1」Flair
    Luogu P4321 随机漫游
    「WC2018」通道
    「CTSC2018」暴力写挂
    关于二项式相乘
    BZOJ #3625 CF #438E 小朋友和二叉树
    GIS可视化
    微信小程序Promise对象
    SQL Server-执行计划教会我如何创建索引
    IIS+NGINX 负载web服务器
  • 原文地址:https://www.cnblogs.com/hbyer/p/10181170.html
Copyright © 2011-2022 走看看