bzoj4448 [Scoi2015]情报传递 树链剖分+树状数组

来源:互联网 发布:软件销售代理协议 编辑:程序博客网 时间:2024/06/05 23:47

题目大意:
维护一颗树,支持一下操作(可以离线)
1、给一个点赋值;
2、查询一条链上比有多少个点以及某个数(i-c)小的点有多少个。

(我这个题目大意略精简了一点哈=。=,但是还是可以比较轻松的把原题目转化成这个意思的)

题目分析:
我们可以把所有的操作离线出来,把赋值操作按照赋值的大小排序(相当于没排,不知道我这个沙茶为毛要排一下>_<)
然后把所有的询问按照要(i-c)从小到大排序。
树链剖分一下,用树状数组维护dfs序。
扫一遍所有的询问,把小于询问权值的赋值操作的位置在dfs序中改为1。
然后查询树链上1的个数就可以了。

时间复杂度O(mlog^2n)

代码如下:

#include <cstdio>#include <algorithm>#include <iostream>#define N 220000using namespace std;inline int lowbit(int x){ return x&-x; }int n,m,root,sum,cnt;int fir[N],nes[N],v[N],tot=1;int fa[N],dep[N],son[N],sz[N],pos[N],ld[N],top;int fw[N],ans[N],_ans[N];bool mark[N];struct Change{    int x,id;    bool operator < (const Change &c) const  { return id<c.id; }}a[N];struct Query{    int x,y,c,id;    bool operator < (const Query &a) const { return c<a.c; }}q[N];void edge(int x,int y){    v[++tot]=y;    nes[tot]=fir[x];    fir[x]=tot;}void update(int x){    for(;x<=n;x+=lowbit(x))        fw[x]++;}int query(int l,int r){    int ans=0;    for(;r;r-=lowbit(r))        ans+=fw[r];    for(l--;l;l-=lowbit(l))        ans-=fw[l];    return ans;}void dfs1(int c){    dep[c]=dep[fa[c]]+1;    sz[c]=1; son[c]=0;    for(int t=fir[c];t;t=nes[t])    {        dfs1(v[t]);        sz[c]+=sz[v[t]];        if(sz[v[t]]>sz[son[c]]) son[c]=v[t];    }}void dfs2(int c){    pos[c]=++top;    ld[c]=c;    if(son[fa[c]]==c) ld[c]=ld[fa[c]];    if(son[c]) dfs2(son[c]);    for(int t=fir[c];t;t=nes[t])    {        if(v[t]==son[c]) continue;        dfs2(v[t]);    }}void solve(int c){    int x=q[c].x,y=q[c].y;    int id=q[c].id;    while(ld[x]!=ld[y])    {        if(dep[ld[x]]<dep[ld[y]]) swap(x,y);        ans[id]+=pos[x]-pos[ld[x]]+1;        _ans[id]+=query(pos[ld[x]],pos[x]);        x=fa[ld[x]];    }    if(dep[x]<dep[y]) swap(x,y);    ans[id]+=pos[x]-pos[y]+1;    _ans[id]+=query(pos[y],pos[x]);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",&fa[i]);        if(fa[i]==0) root=i;        else edge(fa[i],i);    }    dfs1(root); dfs2(root);    scanf("%d",&m);    for(int i=1,opt,x,y,z;i<=m;i++)    {        scanf("%d",&opt);        if(opt==1)        {            cnt++;            scanf("%d%d%d",&q[cnt].x,&q[cnt].y,&q[cnt].c);            q[cnt].id=cnt;            q[cnt].c=i-q[cnt].c;        }        else        {            scanf("%d",&x);            if(!mark[x])            {                sum++;                if(!mark[x]) mark[x]=true;                a[sum].x=x; a[sum].id=i;            }        }    }    sort(a+1,a+sum+1);    sort(q+1,q+cnt+1);    int now=1;    for(int i=1;i<=cnt;i++)    {        while(now<=sum && a[now].id<q[i].c) update(pos[a[now].x]),now++;        solve(i);    }    for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i],_ans[i]);    return 0;}
原创粉丝点击