bzoj3626[LNOI2014] LCA

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626

题目大意:

给出一个n个节点的有根树(编号为0到n-1,根节点为0),q个询问。求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和。

n,q<=5,0000 答案mod 201314
p.s.根的深度为1


========这是道好题 想不到再看(然而找题解的肯定都是跟我一样想不到的orz=========

【↑这个人是zz 别管= =

题解:

这个好题啊..然而想了好久之后滚去看大神博客了(/v \ )
---------------------------------
首先,如何通过路径操作求得x与y的lca的深度咧?
-先将x到根路径上的点的权值+1,然后询问y到根路径上点的权值和,这个权值和就是x与y的lca的深度√
而且非常好的一点就是,这个权值和是可以累加的。这是什么意思咧?
-比如询问是[1,3]跟4的,那么分别将1,2,3到根搞一次(这个时候权值是累加的啊= =),再查询4到根上点的权值和,就得到了[1,3]分别跟4的lca的深度的和了....(感觉好废话orz)
知道了这两个,就好做啦~
把询问离线后排序一下,依次搞搞就好了√


上代码 (忘了改回lld..PE了TAT)..

啊 真的 naive的我以为加了读入优化会快很多,然而、结果、并不会= =

那些1s-的是怎么跑的求告知!!!

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define mod 201314
#define maxn 50100

struct node
{
	int x,y,c,next;
}a[maxn];
int len,first[maxn];
struct tree
{
	int l,r,lc,rc;LL c,la;//c-权值 la-lazy标志
}tr[maxn*2];int trlen;
struct xw
{
	int x,id,c;LL ans;
	//id-存编号 最后搞原询问顺序时排序用的 x,c不造怎么描述看下面意会吧orz
}as[maxn*2];
int top[maxn],dep[maxn],son[maxn];
int z=0,ys[maxn],tot[maxn],fa[maxn];
bool cmp1(xw x,xw y) {return x.x<y.x;}
bool cmp2(xw x,xw y) {return x.id<y.id;}
int read()
{
	char ch=getchar();
    for (;ch>'9'||ch<'0';ch=getchar());
    int tmp=0;
    for (;'0'<=ch && ch<='9';ch=getchar())
      tmp=tmp*10+int(ch)-48;
    return tmp;
}
void ins(int x,int y)
{
	len++;
	a[len].x=x;a[len].y=y;
	a[len].next=first[x];first[x]=len;
}
void dfs1(int x)
{
	tot[x]=1;son[x]=0;
	for (int k=first[x];k!=-1;k=a[k].next)
	{
		int y=a[k].y;
		if (y!=fa[x])
		{
			dep[y]=dep[x]+1;
			fa[y]=x;
			dfs1(y);
			if (tot[son[x]]<tot[y]) son[x]=y;
			tot[x]+=tot[y];
		}
	}
}
void dfs2(int x,int tp)
{
	ys[x]=++z;top[x]=tp;
	if (son[x]!=0) dfs2(son[x],tp);
	for (int k=first[x];k!=-1;k=a[k].next)
	{
		int y=a[k].y;
		if (y!=fa[x] && y!=son[x])
		 dfs2(y,y);
	}
}
void bt(int l,int r)
{
	trlen++;int now=trlen;
	tr[now].l=l;tr[now].r=r;
	tr[now].lc=tr[now].rc=-1;
	tr[now].c=tr[now].la=0;
	if (l<r)
	{
		int mid=(l+r)>>1;
		tr[now].lc=trlen+1;bt(l,mid);
		tr[now].rc=trlen+1;bt(mid+1,r);
	}
}
void updata(int now,int lc,int rc)
{
	if (tr[now].la!=0)
	{
		int l=tr[lc].l,r=tr[lc].r;
		tr[lc].c+=(r-l+1)*tr[now].la;
		tr[lc].la+=tr[now].la;
		l=tr[rc].l;r=tr[rc].r;
		tr[rc].c+=(r-l+1)*tr[now].la;
		tr[rc].la+=tr[now].la;
		tr[now].la=0;
	}
}
void change(int now,int l,int r)
{
	if (tr[now].l==l && tr[now].r==r)
	{
		tr[now].c+=r-l+1;
		tr[now].la++;
		return;
	}
	int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
	updata(now,lc,rc);
	if (r<=mid) change(lc,l,r);
	else if (l>mid) change(rc,l,r);
	else change(lc,l,mid),change(rc,mid+1,r);
	tr[now].c=tr[lc].c+tr[rc].c;
}
int query(int now,int l,int r)
{
	if (tr[now].l==l && tr[now].r==r) return tr[now].c;
	int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
	updata(now,lc,rc);
	if (r<=mid) return query(lc,l,r);
	else if (l>mid) return query(rc,l,r);
	else return query(lc,l,mid)+query(rc,mid+1,r);
}
void add(int x)
{
	int tx=top[x];
	while (x)
	{
		change(1,ys[tx],ys[x]);
		x=fa[tx];tx=top[x];
	}
}
int ask(int x)
{
	int ans=0,tx=top[x];
	while (x)
	{
		ans+=query(1,ys[tx],ys[x]);
		x=fa[tx];tx=top[x];
	}
	return ans;
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int n,m,i,x,y,l,r,c,k;
	//scanf("%d%d",&n,&m);
	n=read();m=read();
	len=0;memset(first,-1,sizeof(first));
	for (i=2;i<=n;i++)
	{
		//scanf("%d",&x);
		x=read();
		x++;ins(x,i);
	}
	dep[1]=1;fa[1]=0;dfs1(1);
	z=0;dfs2(1,1);
	trlen=0;bt(1,n);
	for (i=1;i<=m;i++)
	{
		//scanf("%d%d%d",&x,&y,&c);
		x=read();y=read();c=read();
		x++;y++;c++;
		as[i*2-1].x=x-1;as[i*2-1].id=i*2-1;as[i*2-1].c=c;
		as[i*2].x=y;as[i*2].id=i*2;as[i*2].c=c;
	}sort(as+1,as+m+m+1,cmp1);
	for (k=1,i=0;i<=n;i++)
	{
		add(i);
		for (;as[k].x==i;k++)
		  as[k].ans=ask(as[k].c);
	}sort(as+1,as+m+m+1,cmp2);
	for (i=1;i<=m;i++)
		printf("%I64d\n",(as[i*2].ans-as[i*2-1].ans)%mod);
	return 0;
}



posted @ 2016-09-09 13:57  OxQ  阅读(154)  评论(0编辑  收藏  举报