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

    BZOJ
    Description
    给出一个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的最近公共祖先的深度之和)
    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
    

    HINT
    共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

    sol

    ppl跟我讲这个东西叫做“奇技淫巧”,一看这种东西就应该是ppl这种人说的吧
    所谓“奇技淫巧”在前面的一道题里面讲过,给个链接HNOI2015开店
    就是说,要求的(dis_{lca}),就是两点链交的长度。
    那么对于一个询问(l_i),(r_i),(z_i),我们只要把(l_i)(r_i)的点在树上做一个到根的路径覆盖(路径上权值全部加1),再查一下(z_i)到根的权值和就行了。
    发现可离线,把所有询问输入后按(l_i)或是(r_i)排序,然后做就可以了呀。
    树链剖分(O(nlog^2n))小常数,(Link - cut)(O(nlogn))大常数
    所以应该还是树剖要快一点吧

    code

    因为以前没写过带标记的LCT所以就交了一发LCT

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int mod = 201314;
    const int N = 50005;
    int n,m,fa[N],ls[N],rs[N],rev[N],sz[N],val[N],sum[N],pls[N],Stack[N],top,ans[N];
    struct query{
    	int id,z,pos,opt;
    	bool operator < (const query &b) const
    		{return pos<b.pos;}
    }q[N<<1];
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    void pushup(int x)
    {
    	sz[x]=sz[ls[x]]+sz[rs[x]]+1;
    	sum[x]=(sum[ls[x]]+sum[rs[x]]+val[x])%mod;
    }
    void reverse(int x){swap(ls[x],rs[x]);rev[x]^=1;}
    void cover(int x,int num)
    {
    	(val[x]+=num)%=mod;
    	(sum[x]+=1ll*sz[x]*num%mod)%=mod;
    	(pls[x]+=num)%=mod;
    }
    void pushdown(int x)
    {
    	if (rev[x])
    	{
    		if (ls[x]) reverse(ls[x]);
    		if (rs[x]) reverse(rs[x]);
    		rev[x]=0;
    	}
    	if (pls[x])
    	{
    		if (ls[x]) cover(ls[x],pls[x]);
    		if (rs[x]) cover(rs[x],pls[x]);
    		pls[x]=0;
    	}
    }
    void R_rotate(int x)
    {
        int y=fa[x],z=fa[y];
        ls[y]=rs[x];
        if (rs[x]) fa[rs[x]]=y;
        fa[x]=z;
        if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
        rs[x]=y;fa[y]=x;
        pushup(y);
    }
    void L_rotate(int x)
    {
        int y=fa[x],z=fa[y];
        rs[y]=ls[x];
        if (ls[x]) fa[ls[x]]=y;
        fa[x]=z;
        if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
        ls[x]=y;fa[y]=x;
        pushup(y);
    }
    void splay(int x)
    {
        Stack[top=1]=x;
        for (int i=x;!isroot(i);i=fa[i])
            Stack[++top]=fa[i];
        while (top) pushdown(Stack[top--]);
        while (!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if (isroot(y))
                if (x==ls[y]) R_rotate(x);
                else L_rotate(x);
            else
                if (y==ls[z])
                    if (x==ls[y]) R_rotate(y),R_rotate(x);
                    else L_rotate(x),R_rotate(x);
                else
                    if (x==ls[y]) R_rotate(x),L_rotate(x);
                    else L_rotate(y),L_rotate(x);
        }
        pushup(x);
    }
    void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);}
    void makeroot(int x){access(x);splay(x);reverse(x);}
    void split(int x,int y){makeroot(x);access(y);splay(y);}
    void link(int x,int y){makeroot(x);fa[x]=y;}
    int main()
    {
    	n=gi();m=gi();
    	for (int i=2;i<=n;i++)
    	{
    		int u=gi()+1;
    		link(u,i);
    	}
    	for (int i=1;i<=m;i++)
    	{
    		int l=gi()+1,r=gi()+1,u=gi()+1;
    		q[i]=(query){i,u,l-1,-1};
    		q[i+m]=(query){i,u,r,1};
    	}
    	sort(q+1,q+2*m+1);
    	int j=1;
    	while (!q[j].pos&&j<=2*m) ++j;
    	for (int i=1;i<=n;i++)
    	{
    		split(i,1);
    		cover(1,1);
    		while (j<=2*m&&q[j].pos==i)
    		{
    			split(q[j].z,1);
    			ans[q[j].id]=(ans[q[j].id]+q[j].opt*sum[1]%mod+mod)%mod;
    			++j;
    		}
    	}
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]%mod);
    	return 0;
    }
    
    
  • 相关阅读:
    深入单机事务
    事务的本质
    云计算是什么?
    linux命令之tail
    linux命令之rpm
    String、StringBuffer与StringBuilder区别
    自定义今天的520
    logback中MDC使用
    数组(转载)
    spring获取webapplicationcontext,applicationcontext几种方法详解(转载)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8178710.html
Copyright © 2011-2022 走看看