码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4448: [Scoi2015]情报传递

时间:2018-03-18 17:16:00      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:个数   ems   ace   merge   last   cst   权值线段树   gpo   std   

一眼上去,嗯,这题主席树,码量太大了周末再做。

今天,诶好像还要树剖?

对于每一条重链,用主席树维护,主席树建立权值线段树,求区间的值的个数。

发现是在线修改(冒汗我忘了主席树怎么这样搞)

然后Rose说离线就可以了。(机智)

然后飞快的码,调了调数据。结果第一次T掉了,要数据,调不出来,被肉丝和星感大神联合D飞,树剖模版打错了。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct node
{
    int x,y,next;
}a[210000];int len,last[210000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}

int fa[210000],son[210000],tot[210000],dep[210000];
void pre_tree_node(int x)
{
    tot[x]=1;son[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        dep[y]=dep[x]+1;
        pre_tree_node(y);
        if(tot[y]>tot[son[x]])son[x]=y;
        tot[x]+=tot[y];
    }
}
int z,ys[210000],tp[210000];
void pre_tree_edge(int x,int t)
{
    ys[x]=++z;tp[x]=t;
    if(son[x]!=0)pre_tree_edge(son[x],t);
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=son[x])pre_tree_edge(y,y);
    }
}

//----------composition-------------- 

struct chairmantree
{
    int lc,rc,c;
}tr[4100000];int trlen,rt[210000];
int maketree(int now,int l,int r,int p)
{
    if(now==0)now=++trlen;
    tr[now].c++;
    if(l<r)
    {
        int mid=(l+r)/2;
        if(p<=mid)tr[now].lc=maketree(tr[now].lc,l,mid,p);
        else       tr[now].rc=maketree(tr[now].rc,mid+1,r,p);
    }
    return now;
}
int merge(int x,int y)
{
    if(x==0||y==0)return x+y;
    tr[x].c+=tr[y].c;
    tr[x].lc=merge(tr[x].lc,tr[y].lc);
    tr[x].rc=merge(tr[x].rc,tr[y].rc);
    return x;
}
int getsum(int x,int y,int l,int r,int ll,int rr)
{
    if(x==0&&y==0)return 0;
    if(l==ll&&r==rr)return tr[y].c-tr[x].c;
    int mid=(l+r)/2;
           if(rr<=mid)return getsum(tr[x].lc,tr[y].lc,l,mid,ll,rr);
    else if(mid+1<=ll)return getsum(tr[x].rc,tr[y].rc,mid+1,r,ll,rr);
    else return getsum(tr[x].lc,tr[y].lc,l,mid,ll,mid)+getsum(tr[x].rc,tr[y].rc,mid+1,r,mid+1,rr);
}

//-------------chairmantree------------

int n;
int solve(int x,int y,int c)
{
    int sum=0,ans=0;
    int tx=tp[x],ty=tp[y];
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty]){swap(x,y);swap(tx,ty);}
        if(c>=1)ans+=getsum(rt[ys[ty]-1],rt[ys[y]],1,n,1,c);
        sum+=dep[y]-dep[ty]+1;
        y=fa[ty];ty=tp[y];
    }
    
    if(dep[x]>dep[y])swap(x,y);
    if(c>=1)ans+=getsum(rt[ys[x]-1],rt[ys[y]],1,n,1,c);
    sum+=dep[y]-dep[x]+1;
    printf("%d %d\n",sum,ans);
}

struct change
{
    int x,c;
}C[210000];int clen;
bool cmp(change n1,change n2){return ys[n1.x]<ys[n2.x];}
struct query
{
    int x,y,c;
}q[210000];int qlen;
int main()
{
//    freopen("message.in","r",stdin);
//    freopen("message.out","w",stdout);
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&fa[i]);
        if(fa[i]!=0)ins(fa[i],i);
    }
    dep[1]=1;pre_tree_node(1);
    z=0;pre_tree_edge(1,1);
    
    trlen=0;memset(rt,0,sizeof(rt));
    int m,op,x,y,c;
    scanf("%d",&m);qlen=0;clen=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d",&x,&y,&c);
            qlen++;q[qlen].x=x;q[qlen].y=y;q[qlen].c=i-c-1;
        }
        else
        {
            scanf("%d",&x);
            clen++;C[clen].x=x;C[clen].c=i;
        }
    }
    sort(C+1,C+clen+1,cmp);
    int ctip=1;
    for(int i=1;i<=z;i++)
    {
        if(i==ys[C[ctip].x])
        {
            rt[i]=maketree(rt[i],1,n,C[ctip].c);
            ctip++;
        }
        else {rt[i]=++trlen;tr[trlen].c=0;}
        rt[i]=merge(rt[i],rt[i-1]);
    }
    for(int i=1;i<=qlen;i++)
        solve(q[i].x,q[i].y,q[i].c);
    return 0;
}

 

bzoj4448: [Scoi2015]情报传递

标签:个数   ems   ace   merge   last   cst   权值线段树   gpo   std   

原文地址:https://www.cnblogs.com/AKCqhzdy/p/8595988.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!