• BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序


    BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序

    Description

    由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园。现有一片空地,由乃已经规划n个地点准备种上蔬菜。最新鲜的蔬菜需有最甘甜井水的灌溉,因此由乃将要打出两口井,分别记为井A、井B。现在问题来了,由乃可是一周目的神,为何要打井?是谁想出来的这些题面?由乃不善于搞事情,于是提出以下几个方法,再根据这些方法找出题人。方法如下:
    1. 做完这个出题人出的所有题
    2. 做完所有数据结构题
    3. 出一道奇怪的数据结构题,而且卡常卡死所有做题的
    至于为什么这样能找到出题人呢。。。我也不信她能找到我。。。(能找到岂不是更好?)
    因为由乃是神,所有她有很多秒时间,她终于做完了世界上左右的数据结构题
    于是该她出题了,她左思右想,出了一个简单数据结构题:
    给你一个n个点的有根树,1为根,带边权,有m次操作。
    1、求x的子树中第k小的深度的值,如果子树中没有k个点则输出-1;
    2、将x与x父亲的边权加上k。
    保证每次操作2的k以及原树的边权小于等于一个数len。
    如果操作2中x为1,那么视为将x的基础深度加上了k。
    由乃能不能找到出题人呢?

    Input

    第一行三个数n,m,len。
    之后n - 1行每行两个数表示2~n每个点的父亲编号,以及他们到父亲的边权。。。
    之后m行每行三个数 opt,x,k,opt表示操作种类,x,k意义如题所述。
    n,m <= 100000

    Output

    对于每个操作1,输出一个数表示答案

    Sample Input

    3 5 3
    1 3
    2 3
    1 1 3
    2 3 3
    1 1 3
    2 1 2
    1 1 3

    Sample Output

    6
    9
    11

    HINT

    对于所有数据,n,m <= 100000,len <= 10
    因为出题人是sb,len <= 10,其实没有这个限制也可以解决这个问题

    先用dfs序转化成区间问题。区间加,区间第K小。
    可以二分答案转化为区间求比x小的数的个数,即每块维护一个有序二元组,表示数值和位置。
    然后修改整块加标记,零散块暴力归并,时间复杂度$O(sqrt n)$,询问对零散块暴力然后整块的二分,时间复杂度$O(sqrt nlogn)$。
    也就是说加上二分答案后时间复杂度为$O(nsqrt nlognlogn)$,过不去此题,考虑修改块的大小。
    设块大小为$size$,修改的复杂度是$O(size+n/size)$,查询的复杂度为$O((size+n/size)logn)$,如果我们把零散块预先合在一起可以优化到$O(size+n/size*logn)$。
    算出$size=sqrt nlogn$时最优,总时间复杂度为$O(nsqrt nlogn)$。
    然而复杂度对了写的丑还是过不去。。。加上register直接快了10秒多,然后因为我写的修改常数太大,块的大小应小一点更好。
    手动测试是当块大小为3700时能过。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    using namespace std;
    #define RR register
    inline char nc() {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd() {
        RR int x=0;RR char s=nc();
        while(s<'0'||s>'9') s=nc();
        while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
        return x;
    }
    #define N 100500
    int head[N],to[N],nxt[N],val[N],cnt,dfn[N],son[N],L[N],R[N],block,dis[N],n,m,pos[N],mx,t[N],more[N],size,fa[N],tot;
    struct A {
        int v,id;
    }a[N],b[N],c[N];
    inline bool cmp1(const A &x,const A &y) {
        return x.v<y.v;
    }
    inline void add(int u,int v,int w) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
    }
    void dfs(int x) {
        RR int i; dfn[x]=++tot; a[tot].v=dis[x]; a[tot].id=tot;
        for(i=head[x];i;i=nxt[i]) {
            dis[to[i]]=dis[x]+val[i];
            dfs(to[i]);
        }
        son[x]=tot;
    }
    inline void update(int l,int r,int v) {
        RR int p=pos[l],q=pos[r],i,j,k;
        RR int lb=0,lc=0;
        if(p==q) {
            for(i=L[p];i<=R[p];i++) {
                if(a[i].id<=r&&a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
                else c[++lc]=a[i];
            }
            i=1; j=1; k=L[p];
            while(i<=lb&&j<=lc) {
                if(b[i].v<=c[j].v) a[k++]=b[i++];
                else a[k++]=c[j++];
            }
            while(i<=lb) a[k++]=b[i++];
            while(j<=lc) a[k++]=c[j++];
        }else {
            for(i=p+1;i<q;i++) more[i]+=v;
     
            lb=0,lc=0;
            for(i=L[p];i<=R[p];i++) {
                if(a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
                else c[++lc]=a[i];
            }
            i=1; j=1; k=L[p];
            while(i<=lb&&j<=lc) {
                if(b[i].v<=c[j].v) a[k++]=b[i++];
                else a[k++]=c[j++];
            }
            while(i<=lb) a[k++]=b[i++];
            while(j<=lc) a[k++]=c[j++];
     
            lb=0; lc=0;
            for(i=L[q];i<=R[q];i++) {
                if(a[i].id<=r) b[++lb]=a[i],b[lb].v+=v;
                else c[++lc]=a[i];
            }
            i=1; j=1; k=L[q];
            while(i<=lb&&j<=lc) {
                if(b[i].v<=c[j].v) a[k++]=b[i++];
                else a[k++]=c[j++];
            }
            while(i<=lb) a[k++]=b[i++];
            while(j<=lc) a[k++]=c[j++];
        }
    }
    inline int search(int l,int r,int x) {
        RR int tmp=l,p=pos[l]; r++;
        x-=more[p];
        while(l<r) {
            int mid=(l+r)>>1;
            if(a[mid].v<=x) l=mid+1;
            else r=mid;
        }
        return l-tmp;
    }
    inline int findt(int x) {
        RR int l=1,r=t[0]+1,mid;
        while(l<r) {
            mid=(l+r)>>1;
            if(t[mid]<=x) l=mid+1;
            else r=mid;
        }
        return l-1;
    }
    inline int query(int x,int y,int k) {
        if(y-x+1<k) return -1;
        RR int p=pos[x],q=pos[y],i,j;
        if(p==q) {
            t[0]=0;
            for(i=L[p];i<=R[p];i++) {
                if(a[i].id>=x&&a[i].id<=y) t[++t[0]]=a[i].v+more[p];
            }
        }else {
            t[0]=0;
            RR int lb=0,lc=0;
            for(i=L[p];i<=R[p];i++) {
                if(a[i].id>=x) b[++lb]=a[i],b[lb].v+=more[p];
            }
            for(i=L[q];i<=R[q];i++) {
                if(a[i].id<=y) c[++lc]=a[i],c[lc].v+=more[q];
            }
            i=1; j=1;
            while(i<=lb&&j<=lc) {
                if(b[i].v<=c[j].v) t[++t[0]]=b[i++].v;
                else t[++t[0]]=c[j++].v;
            }
            while(i<=lb) t[++t[0]]=b[i++].v;
            while(j<=lc) t[++t[0]]=c[j++].v;
        }
        RR int l=0,r=mx+1,mid,re;
        while(l<r) {
            mid=(l+r)>>1; re=0;
            if(t[0]) re+=findt(mid);
            for(i=p+1;i<q;i++) re+=search(L[i],R[i],mid);
            if(re>=k) r=mid;
            else l=mid+1;
        }
        return l;
    }
    int main() {
        //freopen("a.in","r",stdin);
        //freopen("a.out","w",stdout);
        RR int kitty,opt;
        n=rd(); m=rd(); kitty=rd();
        RR int i,x,y,j;
        // int ln=n,lg=1;
        // while(ln) lg++,ln>>=1;
        for(i=2;i<=n;i++) {
            x=rd(); y=rd(); add(x,i,y);
        }
        // size=((int)ceil(sqrt(n)))*(lg);
        // printf("%d
    ",size);return 0;
        size=3700;
        dfs(1);
        block=n/size;
        for(i=1;i<=block;i++) {
            L[i]=R[i-1]+1; R[i]=i*size;
            sort(a+L[i],a+R[i]+1,cmp1);
            mx=max(mx,a[R[i]].v);
            for(j=L[i];j<=R[i];j++) pos[j]=i;
        }
        if(R[block]!=n) {
            block++; L[block]=R[block-1]+1; R[block]=n;
            sort(a+L[block],a+n+1,cmp1);
            for(i=L[block];i<=n;i++) pos[i]=block;
            mx=max(mx,a[n].v);
        }
        while(m--) {
            opt=rd(); x=rd(); y=rd();
            if(opt==1) {
                printf("%d
    ",query(dfn[x],son[x],y));
            }else {
                update(dfn[x],son[x],y); mx+=y;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Vue双向绑定的实现原理系列(一):Object.defineproperty
    TCP协议中的三次握手和四次挥手
    一切事物皆对象_进阶篇
    一切事物皆对象_基础篇
    自成一派的正则表达式
    超好用的模块
    软件目录开发规范
    迭代器与生成器
    不怎么好吃的语法糖
    你可造什么是函数
  • 原文地址:https://www.cnblogs.com/suika/p/9033295.html
Copyright © 2020-2023  润新知