[연구 노트] 블록

서문 : I 블록 매우 낮은 수준으로 인해, 너무 멋진 잘못된 다양한있을 수 있습니다, 볼을 지적하시기 바랍니다, 감사합니다.

(기본적으로 여기어려운치즈를 제공 블록, 내가 쓰기에는 너무 게으른)

자주하는 질문

Q : 어떤 분할은?

A : 하이 엔드 폭력, 특히 질문과 동일한 주에서 복잡성의 정도를 수정하려고하는 것입니다, 같은 질문 (예 : 일반적으로 더 높은 (수정) 복잡 묻는 \ (\ 세타 (N) \ ) ), 수정 () 낮은 복잡도 (예 요청 \ (\ 세타 (1) \) ), 만약 둘 도달 \ (\ 세타 (\ N- 형 SQRT) \) , 문제가 될 수있는보다 효율적인 솔루션.

Q : 블록 만합니까?

답변 : 질문이 외에도, 순수한 블록있을 것 \ (폴리 로그 \) 연습 ...

正题

CF1178G

질문의 의미 :

각 포인트에 대한 두 개의 숫자가있는, 뿌리 트리 주어 \ (A_I, b_i \에서 [ -5000,5000] \) 의 가중치로 정의
\ [\ 버트 \ sum_ {w \에서 R (V)} a_w \ 수직 \ CDOT \ 수직 \ sum_ {W \에서 R & LT (V)} B_W \ 수직 \]
(\ (R LT (X) \) 로 정의된다 ) \ X (\ 간단한 경로의 루트 노드에 대한 모든 노드)

두 작업

VX 1 : \ (a_v + X = (x> 0) \)

Qiuzi 트리 : 2 V \ (V \) 최대 무게의 값

\ (\ 텍스트 {한계} n은 그 \ 100,000 \)

해결 방법 :

관찰 \ (B_i는 \) 실제로 전처리 할 수 고정

대답은 ({- 분 (V_I) V_I \} \ 최대 \) \ (또한 부정적인 공정)

그럼 실제로 동적 수요 것을 발견 \ (KX + B \) 인 최대 값 ( \ (B \ K하는 \ 향하는 화살표 X, A'B '\ 향하는 화살표 B \) 향하는 화살표 초기 중량 상수이다)

사실, 볼록 선체에서 가장 큰 컷 절편이다

다음 우리는 따를 수 \ (DFN \) 블록으로 오프셋 중간 표시된 각 블록 \ (태그 \) (태그의 볼록 선체의 이동 위로 위치), 재구성 된 블록 폭력 코너 (초기 값 + (\ B는 * X = \) ), 발견 \ (태그 \) 그래서 직접 폭력 이동 절반 충분히 백업이 필요하지 않습니다, 모노 사이토 겐.

코드는 비교적 명확하다

//Love and Freedom.
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 20021225
#define N 200010
#define BS 505
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct edge{int to,lt;}e[N<<1];
int n,m,q;
int in[N],cnt,dfn[N],idfn[N],sz[N],a[N],b[N],A[N],B[N];
void add(int x,int y)
{
    e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt;
    e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt;
}
struct poi
{
    ll x,y;
    poi(){}
    poi(ll _x,ll _y){x=_x,y=_y;} 
    ll val(int _x){return x*_x+y;}
};
poi operator-(poi a,poi b){return poi(a.x-b.x,a.y-b.y);}
ll cross(poi a,poi b){return a.x*b.y-a.y*b.x;}
struct que
{
    poi q[BS]; int hd,tl;
    void init(){hd=1; tl=0;}
    void push(poi a){q[++tl]=a;}
    void addpoi(ll x,ll y)
    {
        poi ins=poi(x,y);
        while(hd<tl && cross(q[tl]-q[tl-1],ins-q[tl-1])>=0) tl--; push(ins);
    }
    ll query(int x)
    {
        ll ans=-1e18;
        while(hd<tl && q[hd].val(x)<=q[hd+1].val(x))    hd++; if(hd<=tl)    ans=max(ans,q[hd].val(x));
        return ans;
    }
};
bool cmp(int x,int y){return B[x]<B[y];}
struct block
{
    que up,dn; int l,r,sz,num[BS],tag;
    ll query(){return max(up.query(tag),dn.query(tag));}
    void build()
    {
        up.init(); dn.init(); sz=r-l+1;
        for(int i=l;i<=r;i++)   num[i-l+1]=i;
        sort(num+1,num+sz+1,cmp);
        for(int i=1;i<=sz;i++)
            up.addpoi(B[num[i]],1ll*A[num[i]]*B[num[i]]);
        reverse(num+1,num+sz+1);
        for(int i=1;i<=sz;i++)
            dn.addpoi(-B[num[i]],-1ll*A[num[i]]*B[num[i]]);
    }
}kk[BS];
int tms;
void dfs(int x,int fr)
{
    sz[x]=1; dfn[x]=++tms; idfn[tms]=x;
    a[x]+=a[fr]; b[x]+=b[fr];
    for(int i=in[x];i;i=e[i].lt)
    {
        int y=e[i].to; if(y==fr)    continue;
        dfs(y,x); sz[x]+=sz[y];
    }
}
int bel[N];
void init()
{
    m=sqrt(n); int bk=(n+m-1)/m;
    for(int i=1;i<=bk;i++)
    {
        kk[i].l=(i-1)*m+1; kk[i].r=min(i*m,n);
        for(int j=kk[i].l;j<=kk[i].r;j++)
            bel[j]=i;
        kk[i].build();
    }
}
void modify(int l,int r,int v)
{
    if(bel[l]==bel[r])
    {
        for(int i=l;i<=r;i++)   A[i]+=v;
        kk[bel[l]].build(); return;
    }
    
    for(int i=l;i<=kk[bel[l]].r;i++)    A[i]+=v; kk[bel[l]].build();
    for(int i=kk[bel[r]].l;i<=r;i++)    A[i]+=v; kk[bel[r]].build();
    for(int i=bel[l]+1;i<bel[r];i++)    kk[i].tag+=v;
}
ll query(int l,int r)
{
    ll ans=-1e18;
    if(bel[l]==bel[r])
    {
        for(int i=l;i<=r;i++)
            ans=max(ans,1ll*abs(A[i]+kk[bel[l]].tag)*B[i]);
        return ans;
    }
    
    for(int i=l;i<=kk[bel[l]].r;i++)
        ans=max(ans,1ll*abs(A[i]+kk[bel[l]].tag)*B[i]);
    for(int i=kk[bel[r]].l;i<=r;i++)
        ans=max(ans,1ll*abs(A[i]+kk[bel[r]].tag)*B[i]);
    for(int i=bel[l]+1;i<bel[r];i++)
        ans=max(ans,kk[i].query());
    return ans;
}
int main()
{
    n=read(),q=read();
    for(int i=2;i<=n;i++)   add(read(),i);
    for(int i=1;i<=n;i++)   a[i]=read();
    for(int i=1;i<=n;i++)   b[i]=read();
    dfs(1,0);
    for(int i=1;i<=n;i++)   A[i]=a[idfn[i]],B[i]=abs(b[idfn[i]]);
    init();
    while(q--)
    {
        int ty=read(),x=read();
        if(ty==1)
        {
            int v=read();
            modify(dfn[x],dfn[x]+sz[x]-1,v);
        }
        else
        {
            printf("%I64d\n",query(dfn[x],dfn[x]+sz[x]-1));
        }
    }
    return 0;
}
[Ynoi2018] 결국 무엇을 할까? 어떤이 비어 있지? 당신은 그것을 저장할 수 있습니까?

\ (\ 컬러 {레드} {\ 텍스트 {경고}} \) :이 코드는 정확성을 보장하기 위해, 과거에 카드입니다.

질문의 의미 :

플러스 간격 (양의 정수), 가장 큰 서브 세그먼트 범위.

\ (\ 텍스트 {한계} : n \ 100,000 당량 \)

해결 방법 :

우선 유지 기능을 수행하는 전체적인 상황을 고려 \ (F (X) \) 대표를 \ (+ X \) 분명 않음 볼록 선체 (저급 보스)

유사 유지 보수에 대한 질문 (\ 태그) \ 그리고 우리는 우리가 볼록 선체 블록을 빠르게 유지할 수없는 것을 발견

볼록 선체 참여를 유도하는 방법을 고려

우리는 분할 및 정복 \ ((L, R) \ ) 분명히 \ ((L, 중간) \ ) 와 \ ((중간, R) \ ) 볼록 선체가 재귀를 셀 수

맞은 편 \ (중간 \) 수요의 볼록 선체가 좋지 않다, 그러나 우리는 그것을 수행하는 방법, 우리는 최대 규모의 왼쪽 부분을 결합 할 수 있습니다 이하 세그먼트의 최대 범위의 변경의 단일 지점 생각할 수 접미사 / 접두사와 최대 규모의 오른쪽 부분 (분명히 두 a는 볼록)와 결합 된 패키지는 볼록 갖는다영리하지만 쓸모민코프 스키와 (그 것이다 당신이 찌르지 않는 이 블로그 게시물 에 대해 배울) 할 \ (\ 세타 (N) \ ) 합병.

당신은 완성 된 T 플라이 친구 하하가 그런 후에

어떤 특정 최적화 볼 수 요정 블로그 에 대해 배울 수를

카드는 과거에없는 사용할 수있는 이 문제 정확성을 확인하기 위해

(권한 문제가, 오늘은 물음표 ?? 검은 얼굴 .JPG하지 않을 때 나는 몇 일 전에 쓴 방법)

//Love and Freedom.
#pragma GCC optimize(3)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 100010
#define B 110
#define INF (1ll<<48)
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct poi
{
    ll x,y;
    poi(){}
    poi(ll _x,ll _y){x=_x,y=_y;} 
};
poi operator+(poi a,poi b){return poi(a.x+b.x,a.y+b.y);}
poi operator-(poi a,poi b){return poi(a.x-b.x,a.y-b.y);}
ll cross(poi a,poi b){return a.x*b.y-a.y*b.x;}
struct data{ll l,r,ans,sum;};
data operator+(data a,data b)
{
    data ans;
    ans.l=max(a.l,a.sum+b.l);
    ans.r=max(b.r,b.sum+a.r);
    ans.ans=max(a.ans,max(b.ans,a.r+b.l));
    ans.sum=a.sum+b.sum;
    return ans;
}
void gethull(poi *st,int &top)
{
    int rem=top; top=1;
    for(int i=2;i<=rem;i++)
    {
        while(top>1 && cross(st[i]-st[top-1],st[top]-st[top-1])<=0) top--;
        st[++top]=st[i];
    }
}
poi tmp[B+10]; int n,m;
void insert(poi a){tmp[a.x].y=max(tmp[a.x].y,a.y);}
struct block
{
    int l,r,sz; poi pre[B+10],suf[B+10],ans[B+10]; ll a[B+10];
    data val; ll tag; bool flag; int lsz; int s1,s2,s3,p1,p2,p3;
    int brute(int l,int r) // (l,r]
    {
        ll sum=0; for(int i=l+1;i<=r;i++)   sum+=a[i],ans[i]=poi(i-l,sum);
        for(int i=l+2;i<=r;i++)
        {
            sum=0; for(int j=0;i+j<=r;j++)
                sum+=a[i+j],ans[l+j+1].y=max(ans[l+j+1].y,sum);
        }
        s3=r-l; gethull(ans+l,s3); return s3;
    }
    ll getval(poi a){return a.y+a.x*tag;}
    int solve(int l,int r) // (l,r]
    {
        if(r-l<lsz) return 0; if(r-l<17)    return brute(l,r);
        int mid=l+r>>1;
        int ls=solve(l,mid),rs=solve(mid,r);
        for(int i=1;i<=r-l;i++) tmp[i]=poi(i,-INF);
        for(int i=l+1;i<=l+ls;i++)  insert(ans[i]);
        for(int i=mid+1;i<=mid+rs;i++)  insert(ans[i]);
        ll sum=0; s1=0; for(int i=mid+1;i<=r;i++)   s1++,sum+=a[i],pre[s1]=poi(s1,sum); gethull(pre,s1);
        sum=0; s2=0; for(int i=mid;i>l;i--) s2++,sum+=a[i],suf[s2]=poi(s2,sum); gethull(suf,s2);
        int w1=1,w2=1; insert(pre[w1]+suf[w2]);
        while(w1!=s1&&w2!=s2)
        {
            if(cross(pre[w1+1]+suf[w2]-pre[w1]-suf[w2],pre[w1]+suf[w2+1]-pre[w1]-suf[w2])>=0)   w2++;
            else    w1++; insert(pre[w1]+suf[w2]);
        }
        while(w1!=s1)   w1++,insert(pre[w1]+suf[w2]);
        while(w2!=s2)   w2++,insert(pre[w1]+suf[w2]);
        gethull(tmp,s3=r-l); for(int i=1;i<=s3;i++) ans[l+i]=tmp[i];
        return s3;
    }
    void moveon(poi *a,int &p,int &s)
    {
        while(p<s)  if(getval(a[p])<=getval(a[p+1]))    p++;
        else    return;
    }
    void recons()
    {
        if(tag) for(int i=1;i<=sz;i++)  a[i]+=tag; tag=0;
        if(!flag){flag=1; for(int i=1;i<=sz;i++)    flag&=(a[i]>=0);}
        if(flag){val.sum=0; for(int i=1;i<=sz;i++)  val.sum+=a[i]; val.l=val.r=val.ans=val.sum; return;}
        lsz=ans[p3].x; solve(0,sz);
        ll sum=0; s1=0; for(int i=1;i<=sz;i++)  s1++,sum+=a[i],pre[s1]=poi(s1,sum); gethull(pre,s1);
           sum=0; s2=0; for(int i=sz;i;i--) s2++,sum+=a[i],suf[s2]=poi(s2,sum); gethull(suf,s2);
        p1=p2=p3=1; moveon(pre,p1,s1); moveon(suf,p2,s2); moveon(ans,p3,s3);
        flag&=(p1==s1)&&(p2==s2)&&(p3==s3);
        val=(data){max(pre[p1].y,0ll),max(suf[p2].y,0ll),max(ans[p3].y,0ll),sum};
    }
    void modify(int x)
    {
        if(flag){tag+=x; val.sum+=x*sz; val.l=val.r=val.ans=val.sum; return;}
        tag+=x; moveon(pre,p1,s1); moveon(suf,p2,s2); moveon(ans,p3,s3);
        val=(data){max(0ll,getval(pre[p1])),max(0ll,getval(suf[p2])),max(0ll,getval(ans[p3])),val.sum+x*sz};
    }
    data calc(int l,int r) // [l,r]
    {
        data wei=(data){0,0,0,0}; ll sum=0;
        for(int i=l;i<=r;i++)   sum+=a[i]+tag; wei.sum=sum; sum=0;
        for(int i=l;i<=r;i++)   sum+=a[i]+tag,wei.l=max(wei.l,sum); sum=0;
        for(int i=r;i>=l;i--)   sum+=a[i]+tag,wei.r=max(wei.r,sum); sum=0;
        for(int i=l;i<=r;i++)
        {
            sum+=a[i]+tag; if(sum<0)    sum=0;
            wei.ans=max(wei.ans,sum); 
        }
        return wei;
    }
    ll getans(int l,int r)
    {
        ll sum=0; ll ans=0;
        for(int i=l;i<=r;i++)
        {
            sum+=a[i]+tag; if(sum<0)    sum=0;
            ans=max(sum,ans);
        }
        return ans;
    }
}blo[(N/B)+1]; int bel[N];
void modify(int l,int r,int x)
{
    int id=bel[l],fr=blo[id].l;
    if(bel[l]==bel[r])
    {
        for(int i=l;i<=r;i++)
            blo[id].a[i-fr]+=x;
        blo[id].recons();
        return;
    }
    for(int i=l;i<=blo[id].r;i++)   blo[id].a[i-fr]+=x; blo[id].recons(); id=bel[r],fr=blo[id].l;
    for(int i=blo[id].l+1;i<=r;i++) blo[id].a[i-fr]+=x; blo[id].recons();
    for(int i=bel[l]+1;i<bel[r];i++)    blo[i].modify(x);
}
ll query(int l,int r)
{
    int id=bel[l],fr=blo[id].l;
    if(bel[l]==bel[r])  return blo[id].getans(l-fr,r-fr);
    data qwq=blo[id].calc(l-fr,blo[id].r-fr);
    for(int i=bel[l]+1;i<bel[r];i++)    qwq=qwq+blo[i].val;
    qwq=qwq+blo[bel[r]].calc(1,r-blo[bel[r]].l);
    return qwq.ans;
}
char ch[10];
int main()
{
    n=read(),m=read();
    for(int i=0,id=0;i<=n;i+=B,id++)
    {
        for(int j=1;j<=B&&i+j<=n;j++)   blo[id].a[j]=read(),bel[i+j]=id;
        blo[id].sz=min(n-i,B); blo[id].l=i; blo[id].r=i+B; blo[id].recons();
    }
    while(m--)
    {
        scanf("%s",ch+1); int l=read(),r=read();
        if(ch[1]=='A')  modify(l,r,read());
        else    printf("%lld\n",query(l,r));
    }
    return 0;
}
간격 역순으로

이 간단한 (

해결 방법 :

접두사 / 접미사 역 블록 번호, 다음 모서리 같은 폭력 유지 관리

//Love and Freedom.
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 20021225
#define N 51000
#define B 200
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
int tmp[N];
int solve(int *a,int n)
{
    if(n<=1)    return 0;
    int s1=n>>1,s2=n-s1,ans=solve(a,s1)+solve(a+s1,s2),l=0,r=0,sz=0;
    while(l<s1&&r<s2)
    {
        if(a[l]>a[s1+r])    tmp[sz++]=a[r+s1],r++;
        else    tmp[sz++]=a[l++],ans+=r;
    }
    while(l<s1) tmp[sz++]=a[l++],ans+=s2;
    while(r<s2) tmp[sz++]=a[s1+r],r++; 
    for(int i=0;i<sz;i++)   a[i]=tmp[i];
    return ans;
}
int suf[N][(N/B)+1],pre[N][(N/B)+1]; int a[N+10],n,v[N+10];
int cnt[N]; int bel[N],lb[(N/B)+1],rb[(N/B)+1],blo[(N/B)+1],sz[(N/B)+1],bc,rem[N+10];
int main()
{
    n=read(); for(int i=1;i<=n;i++) v[i]=a[i]=read();
    sort(v+1,v+n+1); int nn=unique(v+1,v+n+1)-v;
    for(int i=1;i<=n;i++)   rem[i]=a[i]=lower_bound(v+1,v+nn,a[i])-v;
    for(int i=1,id=1;i<=n;i+=B,id++)
    {
        for(int j=0;j<B;j++)    cnt[a[i+j]]++,bel[i+j]=id;
        for(int j=1;j<=nn;j++)  cnt[i]+=cnt[i-1];
        for(int j=1;j<i;j++)    pre[j][id]=pre[j-1][id]+cnt[a[j]-1];
        lb[id]=i; rb[id]=min(n,i+B-1); sz[id]=rb[id]-lb[id]+1; blo[id]=solve(a+i,sz[id]);
        bc=id; for(int j=1;j<=nn;j++)   cnt[j]=0;
    }
    for(int i=bc;i;i--)
    {
        int l=lb[i],r=rb[i];
        for(int j=l;j<=r;j++)   cnt[a[j]]++;
        for(int j=1;j<=nn;j++)  cnt[j]+=cnt[j-1];
        for(int j=r+1;j<=n;j++) suf[j][i]=suf[j+1][i]+(sz[i]-cnt[a[j]]);
        for(int j=1;j<=nn;j++)  cnt[j]=0;
    }
    int m=read(),lastans=0;
    while(m--)
    {
        int l=read()^lastans,r=read()^lastans;
        if(bel[l]==bel[r])
        {
            for(int i=l;i<=r;i++)   a[i]=rem[i];
            printf("%d\n",lastans=solve(a+l,r-l+1));
            continue;
        }
        int lid=bel[l],rid=bel[r],tot=0;
        for(int i=l;i<=rb[lid];i++) a[tot++]=rem[i];
        for(int i=lb[rid];i<=r;i++) a[tot++]=rem[i];
        int ans=solve(a,tot);
        for(int i=lid+1;i<rid;i++)  ans+=pre[r][i]-pre[l-1][i]+suf[l][i]-suf[r+1][i]+blo[i];
        printf("%d\n",lastans=ans);
    }
    return 0;
}

나는 삼일 쓴 3 MD에 보인다? ? 8 정말 이해 (

\ (\ 색상 {빨간색} {\ {경고} 텍스트} \) : 나머지 문제는 단지 큰 가능성을 작성하지 않은 그것을 잘못 때문에 읽기

모 보조 오프라인 팀

고려 ([L, R] \ \ ) 에 \ ([L ', R' ] \) 개발

권리 확장을 위해 (R \) \ 응답 증가는 \ (쿼리 (1, R- 1) - 쿼리 (1, L-1) \)

또한 거기에 접미사가 남긴

그것은 쿼리로 변환 될 수있다 \ ([1, R] \ ) 에서 \ (> S [R] \ ) 번호 조회 \ ([1, R] \ ) 에서 \ (> S [A, B ] \ ) 두 수있다 수 \ (\ 세타 (1) \ ) 대답의 총 복잡도 \ (\ 쎄타 (n \ SQRT의 N) \)

전제 : 충족 Subtractivity

블록 14 (하드 버전.)

질문의 의미 :

\ (N- \)\ (A_I \)

마다 소정 간격 \ ([L, R] \ ) 방법 질의 튜플 간격 \ ((I, J) \ ) 를 만족 \ (A_I \) 이다 \ (a_j \) 복수

\ (\ 텍스트 {한계} : N, A_I \ 르 100000 \)

해결 방법 :

차 오프라인 모 팀은 다음 질문으로 전환

쿼리 \ ([1, R] \ ) 이다 \ (S [R & LT] \) / \ (S [A, B] \) 번호 제수 / 복합

하나의 숫자가 전처리 될 수 있습니다에 대해 여러 열거 직접은 전체 블록의 약수를 확인, 수에 대해 얻을 수 있습니다.

파티션의 개수에 대한 고려없이 \ (> \} N-SQRT {\) , 다수의 스캔 라인을 열거 할 수있다 \ (\ 르 \ n-SQRT는 \) 먼저 열거 될 수 없다하고 고려 관여 직접 조작 프리픽스 이 재료에 간격 만 \ (\ SQRT n \) 되도록 \ (\ 쎄타 (\ SQRT N ^ 3) \) 또는 \ (\ 쎄타 (n \ SQRT N) \)

· 매일, 사랑의 실행을 변경

아, 내가 그것을 쓸 너무 게으른 해요 이것 좀 봐

IMG

BZOJ5145
CF896E
UOJ (33)
Uoj435
UOJ337

위는 뻐꾸기의 목록입니다

추천

출처www.cnblogs.com/hanyuweining/p/12208419.html