BZOJ4867 Ynoi2017舌尖上的由乃(dfs序+分块)

  容易想到用dfs序转化为序列上的问题。考虑分块,对每块排序,修改时对于整块打上标记,边界暴力重构排序数组,询问时二分答案,这样k=sqrt(nlogn)时取最优复杂度nsqrt(nlogn)logn,离跑过去还差一点。二分答案这一部分看上去很难优化,考虑重构时不那么暴力,将要修改的和不要修改的部分分别从已排序数组中提出来,归并即可,这样k=sqrt(n)logn时取最优复杂度nsqrt(n)logn。尽管加了一些奇怪的卡常然而并没有什么卵用,bzoj上根本过不掉。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,len,p[N],deep[N],dfn[N],id[N],size[N],t,cnt,s;
int block,num,pos[N],L[N],R[N],lazy[N];
struct data{int to,nxt,len;
}edge[N];
struct data2
{
    int i,x;
    bool operator <(const data2&a) const
    {
        return x<a.x;
    }
}a[N],u[N],v[N],w[N];
struct data3{int i,j,x,op;}Q[N];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
void dfs(int k)
{
    size[k]=1;dfn[k]=++cnt;id[cnt]=k;s=max(s,deep[k]);
    for (int i=p[k];i;i=edge[i].nxt)
    {
        deep[edge[i].to]=deep[k]+edge[i].len;
        dfs(edge[i].to);
        size[k]+=size[edge[i].to];
    }
}
void add(int k,int l,int r,int x)
{
    int n=0,m=0;
    for (int i=L[k];i<=R[k];i++)
    if (a[i].i>=l&&a[i].i<=r) u[++n].i=a[i].i,deep[id[a[i].i]]+=x,u[n].x=a[i].x+x;
    else v[++m]=a[i];
    int p=1,q=1;
    for (int i=L[k];i<=R[k];i++)
    if (u[p].x<v[q].x&&p<=n||q>m) a[i]=u[p++];
    else a[i]=v[q++];
}
int calc(int k,int l,int r)
{
    if (pos[l]==pos[r])
    {
        int s=0;
        for (int i=l;i<=r;i++)
        if (deep[id[i]]+lazy[pos[l]]<=k) s++;
        return s;
    }
    else
    {
        int s=0;
        for (int i=pos[l]+1;i<pos[r];i++)
        s+=upper_bound(a+L[i],a+R[i]+1,(data2){0,k-lazy[i]})-a-L[i];
        for (int i=l;i<=R[pos[l]];i++)
        if (deep[id[i]]+lazy[pos[l]]<=k) s++;
        for (int i=L[pos[r]];i<=r;i++)
        if (deep[id[i]]+lazy[pos[r]]<=k) s++;
        return s;
    }
}
double complexity(double k,double q){return (m-q)*(n/k+3*k)+q*log(s+(m-q)*(len+1>>1))/log(2)*(n/k*log(n)/log(2)+k);}
namespace segmenttree
{
    int L[N<<2],R[N<<2],tree[N<<2],lazy[N<<2];
    void build(int k,int l,int r)
    {
        L[k]=l,R[k]=r,lazy[k]=0;
        if (l==r) {tree[k]=deep[id[l]];return;}
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tree[k]=max(tree[k<<1],tree[k<<1|1]);
    }
    void update(int k,int x){tree[k]+=x,lazy[k]+=x;}
    void down(int k){update(k<<1,lazy[k]),update(k<<1|1,lazy[k]),lazy[k]=0;}
    void add(int k,int l,int r,int x)
    {
        if (L[k]==l&&R[k]==r) {update(k,x);return;}
        if (lazy[k]) down(k);
        int mid=L[k]+R[k]>>1;
        if (r<=mid) add(k<<1,l,r,x);
        else if (l>mid) add(k<<1|1,l,r,x);
        else add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x);
        tree[k]=max(tree[k<<1],tree[k<<1|1]);
    }
    int query(int k,int l,int r)
    {
        if (L[k]==l&&R[k]==r) return tree[k];
        if (lazy[k]) down(k);
        int mid=L[k]+R[k]>>1;
        if (r<=mid) return query(k<<1,l,r);
        else if (l>mid) return query(k<<1|1,l,r);
        else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4867.in","r",stdin);
    freopen("bzoj4867.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();len=read();
    for (int i=2;i<=n;i++)
    {
        int x=read(),y=read();
        addedge(x,i,y);
    }
    dfs(1);segmenttree::build(1,1,n);
    int qwq=0;
    for (int i=1;i<=m;i++)
    {
        int op=read(),k=read(),x=read();
        if (op==1) qwq++;
        Q[i].op=op,Q[i].i=dfn[k],Q[i].j=dfn[k]+size[k]-1,Q[i].x=x;
    }
    block=1;for (int i=2;i<=n;i++) if (complexity(i,qwq)<complexity(block,qwq)) block=i;
    num=(n-1)/block+1;
    for (int i=1;i<=num;i++)
    {
        L[i]=(i-1)*block+1,R[i]=min(n,i*block);
        for (int j=L[i];j<=R[i];j++)
        pos[j]=i,a[j].i=j,a[j].x=deep[id[j]];
        sort(a+L[i],a+R[i]+1);
    }
    for (int i=1;i<=m;i++)
    {
        int l=Q[i].i,r=Q[i].j,x=Q[i].x;
        if (Q[i].op==1)
        {
            int left=1,right=segmenttree::query(1,l,r),ans=-1;
            while (left<=right)
            {
                int mid=left+right>>1;
                if (calc(mid,l,r)>=x) ans=mid,right=mid-1;
                else left=mid+1;
            }
            printf("%d\n",ans);
        }
        else
        {
            segmenttree::add(1,l,r,x);
            if (pos[l]==pos[r]) add(pos[l],l,r,x);
            else
            {
                for (int i=pos[l]+1;i<pos[r];i++) lazy[i]+=x;
                add(pos[l],l,R[pos[l]],x),add(pos[r],L[pos[r]],r,x);
            }
        }
    }
    return 0;
}

 

posted @ 2018-11-24 19:02  Gloid  阅读(196)  评论(0编辑  收藏  举报