【BZOJ4876】 [Zjoi2017]线段树

来源:互联网 发布:java开发平台结构图 编辑:程序博客网 时间:2024/06/01 23:56

考场上想也不想就打了nmlogn的暴力。然后听了lzz dalao的讲解,瞬间感觉好简单。。

先考虑特殊情况,l=1(r=n也一样):

先线段树上跑倍增拿掉最大一段,剩下就跟l<>1一样了

对于一般情况,考虑从[l-1,l-1]和[r+1,r+1]两个节点向上跑,一直跑到这两个点的lca,然后找规律或者各种姿势发现[l,r]的各个线段树节点其实就是:

当[l-1,l-1]跑到某个点(lca和lca的儿子不算哦)时,如果它是它父亲的左儿子,那么右儿子肯定是其中一个线段树节点,[r+1,r+1]刚好完全反过来。

然后考虑ans=number(线段树节点)*deep[u]+sum(线段树节点deep)-2*sum(线段树节点与u的lca深度)

然后前两个东西显然可以一遍dfs维护树上前缀和搞出来(分成左右两种情况),然而其实lca的深度也很好求

还是只考虑左边([l-1,l-1]):

如果u和[l-1,l-1]的lca在整个链的上方(在链外),那所有的(左边的)线段树节点与u的lca都是u和[l-1,l-1]的lca(画图一下啦)

(显然不可能在链下方 下面都没东西啦)如果在链上,就分成两段,在u和[l-1,l-1]的lca的下方的线段树节点,就跟上一种情况一样,在上方的点,lca就是它们本身(这总是显然的了吧)

然后我们就这样过了。。。吗?

等等。。似乎还有一种可能:万一u和某线段树节点的lca就是这个节点呢?我们刚刚似乎算成了它的父亲?没关系嘛,特判减个二嘛。。

(然而窝的常数和length似乎被wlc dalao虐翻了!!看来是时候学习卡常数和压代码技巧了。。。)

#include <bits/stdc++.h>#define gc getchar()#define N 400009#define mp make_pair#define ll long longusing namespace std;ll n,a[N],m,u,l,r,num,son[N][2],Now,Mson[N],f[N][21];ll Num[N][2],sum[N][2],size[N],top[N],father[N],L[N],R[N],deep[N];map<pair<int,int>,int> pos;ll read(){char ch;ll x=1;while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;ll s=ch-'0';while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';return s*x;}void build(ll l,ll r,ll now){L[now]=l,R[now]=r;pos[mp(l,r)]=now;if (l==r) return;ll tmp=++Now;build(l,a[tmp],son[now][0]=++num);build(a[tmp]+1,r,son[now][1]=++num);}void dfs(ll x,ll fa){deep[x]=deep[fa]+1;father[x]=fa;size[x]=1;if (!son[x][0]) return;for (ll i=0;i<2;i++){Num[son[x][i]][i]=Num[x][i]+1;sum[son[x][i]][i]=sum[x][i]+deep[x]+1;Num[son[x][i]][i^1]=Num[x][i^1];sum[son[x][i]][i^1]=sum[x][i^1];dfs(son[x][i],x);size[x]+=size[son[x][i]];if (size[Mson[x]]<size[son[x][i]]) Mson[x]=son[x][i];}}void Dfs(ll x,ll y){top[x]=y;if (!son[x][0]) return;if (Mson[x]) Dfs(Mson[x],y);for (ll i=0;i<2;i++)if (son[x][i]!=Mson[x]) Dfs(son[x][i],son[x][i]);}ll lca(ll x,ll y){for (;top[x]!=top[y];x=father[top[x]])if (deep[top[x]]<deep[top[y]]) swap(x,y);return deep[x]<deep[y]?x:y;}int main(){freopen("ex_segment2.in","r",stdin);freopen("ex_segment.out","w",stdout);n=read();for (ll i=1;i<n;i++) a[i]=read();build(1,n,num=1);dfs(1,0);Dfs(1,1);for (ll i=1;i<=2*n-1;i++) f[i][0]=father[i];for (ll i=1;i<=20;i++)for (ll j=1;j<=2*n-1;j++)f[j][i]=f[f[j][i-1]][i-1];m=read();for (ll i=1;i<=m;i++){u=read(),l=read(),r=read();ll Ln=pos[mp(l-1,l-1)],Rn=pos[mp(r+1,r+1)],Lca,ans=0,lc1,lc2;if (l==1&&r==n){printf("%lld\n",deep[u]-1);continue;}if (l==1){ll now=pos[mp(1,1)];for (ll j=20;j>=0;j--)if (f[now][j]&&R[f[now][j]]<=r) now=f[now][j];ans=deep[now]+deep[u]-2*deep[lca(now,u)];l=R[now]+1;Ln=pos[mp(l-1,l-1)];}if (r==n){ll now=pos[mp(n,n)];for (ll j=20;j>=0;j--)if (f[now][j]&&L[f[now][j]]>=l) now=f[now][j];ans=deep[now]+deep[u]-2*deep[lca(now,u)];r=L[now]-1;Rn=pos[mp(r+1,r+1)];}if (l>r){printf("%lld\n",ans);continue;}//ans=sum[]+Num[]*deep[u]-2*lca_sum[]Lca=lca(Ln,Rn);ans+=sum[Ln][0]+sum[Rn][1]-sum[son[Lca][0]][0]-sum[son[Lca][1]][1];ans+=deep[u]*(Num[Ln][0]+Num[Rn][1]-Num[son[Lca][0]][0]-Num[son[Lca][1]][1]);lc1=lca(Ln,u),lc2=lca(Rn,u);ans-=2*deep[lc1]*(Num[Ln][0]-Num[deep[lc1]>deep[son[Lca][0]]?lc1:son[Lca][0]][0]);ans-=2*deep[lc2]*(Num[Rn][1]-Num[deep[lc2]>deep[son[Lca][1]]?lc2:son[Lca][1]][1]);if (deep[lc1]>deep[son[Lca][0]])ans-=2*(sum[lc1][0]-sum[son[Lca][0]][0]-(Num[lc1][0]-Num[son[Lca][0]][0]));if (deep[lc2]>deep[son[Lca][1]])ans-=2*(sum[lc2][1]-sum[son[Lca][1]][1]-(Num[lc2][1]-Num[son[Lca][1]][1]));if (L[son[lc1][1]]<=L[u]&&R[son[lc1][1]]>=R[u]&&deep[lc1]>=deep[son[Lca][0]])ans-=2;if (L[son[lc2][0]]<=L[u]&&R[son[lc2][0]]>=R[u]&&deep[lc2]>=deep[son[Lca][1]])ans-=2;printf("%lld\n",ans);}return 0;}


0 0