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; }