CodeForces 193d. Segmentos Dos [línea de árboles]

Portal de
hacer esta pregunta es debido a la oportunidad para la última pregunta podrido puente de la Copa de 2013, a pesar de que la cuestión de la violencia podría ir, pero al ver la línea de árboles introducción enfoque Gángster, me siento renovado y sé de una línea de árboles,Efectivamente, la línea de árboles es omnipotente.

El significado de los problemas

Usted da un \ (n \) de la matriz completa \ (A \) , se puede seleccionar a partir de dos secciones no se superponen, si todo lo de las dos secciones están dispuestas en orden ascendente es una tolerancia \ (1 \) de secuencia aritmética, es un programa legítimo, si el mismo intervalo de número contiene dos conjuntos diferentes, a continuación, como un programa. Le pregunté a un total de cuántos programas legítimos.

solución del problema

Considere un número entero positivo en el rango si se sabe \ ([l, r] \ ) en la matriz original completo \ (A \) se divide en la \ (K \) período, momento en el que \ (R & lt 1 + \.) , En el siguiente caso:

  • Si \ (r + 1 \) y \ ([l, r] \ ) a cualquiera de un número no adyacente, entonces \ ([l, r + 1 ] \) se divide en \ (k + 1 \) sección .
  • Si \ (r + 1 \) y \ ([l, r] \ ) en un número de adyacente, entonces \ ([l, r + 1 ] \) todavía está dividida en \ (K \) segmentos.
  • Si \ (r + 1 \) y \ ([l, r] \ ) de dos números adyacentes, entonces \ ([l, r + 1 ] \) se divide en (k-1 \) \ segmento.

En este caso puede ser un \ (O (n ^ 2) \) algoritmo no entrar aquí. Esta pregunta se debe a que los datos de alcance \ (n- \ Le 300 \, 000 \) , \ (O (^ n-2) \) algoritmo no es aceptable.
Sin embargo, de acuerdo con los cambios anteriormente descritos del segmento, hemos encontrado que el intervalo se puede cambiar, es decir, a \ (f [l, r] \) representa \ ([l, r] \ ) número de segmentos a ser dividida, si conocido \ (F [1, R & lt.], F [2, R & lt], ..., F [R & lt, R & lt] \) , se añaden estos intervalos de tiempo \ (R & lt 1 + \.) , las siguientes circunstancias:

  • Si \ ([1, r] \ ) no es el número de los de \ (r + 1 \) en \ (A \) adyacente, entonces:
    . \ [F [I, R & lt + 1] = F [I, R ^ ] 1 \]

  • Si \ ([1, r] \ ) sólo hay un número \ (X \) y \ (r + 1 \) en \ (A \) adyacente, \ ([I, R & lt +. 1] (. 1 \ le i \ le x) \) se divide y el número de segmentos \ ([i, r] \ ) mismo que \ (r + 1 \) es y \ (X \) firmemente colocado junto ♂ cosa; y \ ([i, r + 1 ] (x + 1 \ le i \ le r + 1) \) de \ ([i, r] \ ) número de segmentos dividido por el \ (1 \) , la razón es \ ([ i, r] \) no se cuentan y \ (r + 1 \) adyacente, a continuación, \ (r + 1 \) puede constituir una sección separada. Por lo tanto, este caso puede ser expresada como:
    ... \ [\ La begin {el alineado} F [I, R & lt + 1] y = F [I, R & lt] y, && 1 \ Le & I \ Le X \\ F [I, R & lt + 1] y = f [i, r] 1 y, && x + 1 \ le + i \ le r + 1 \ end {alineado} \]

  • Si \ ([l, r] \ ) hay dos números \ (x, y (x < y) \) y \ (r + 1 \) en \ (A \) adyacente, a continuación, \ ([ i, r + 1] (1 \ le i \ le x) \) el número de etapas se divide la relación \ ([i, r] \ ) menos \ (1 \) , porque originalmente \ (x, y \) es dividida , añadiendo \ (r + 1 \) después de las dos secciones entre sí; y \ ([i, r + 1 ] (x + 1 \ le i \ le y) \) y \ ([i, r] \ ) son iguales, ya que sólo \ (y \) un número y \ (r + 1 \) pegar; y \ ([i, r + 1 ] (y + 1 le \ le \ i r + 1) \) relación \ ( [i, r] \) de múltiples \ (1 \) . Se puede expresar como:
    \ [\ Begin {alineado} f [i, r + 1] y = f [i, r] -1 y, && 1 \ le + i \ le x \\ f [i, r + 1] y = f [i, r] y, && x + 1 \ le + i \ le y \\ f [i, r + 1] y = f [i, r] 1 y, && y + 1 \ le + i \ le r + 1 \ end {alineado } \]

Así que podemos utilizar la línea de árboles para mantener decidir \ (r \) al (f [i, r] \ ) \ valor, de acuerdo con el significado de las preguntas, cada adición \ (r + 1 \) después de sólo necesita consultar la línea de árboles el valor \ (1 \) o \ (2 \) número de nodos de hoja en la lista.

En pocas palabras acerca de la redacción de la línea de árboles

Debido a que en \ (f [l, r] \) propiedades pueden saber que el segmento de línea mínimo de nodos de hoja \ (1 \) , a continuación, para comprobar \ (1 \) y \ (2 \) número, solamente intervalo mínimo de mantenimiento y el valor mínimo y el valor mínimo del número \ (1 + \) número de la lista.
Nota plancha redacción operación, la mínima estadística rango, entonces la pregunta sobre el número mínimo mínimo subárbol, en particular, no se olvide de contar el mínimo completo \ (1 + \) número.

código

#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=3e5+10;
int n,a[N],p[N];

struct SegTree{
    #define mid (l+r>>1)
    int num1[N*4],num2[N*4],minv[N*4],tag[N*4];
    void pushdown(int id){
        minv[id<<1]+=tag[id];tag[id<<1]+=tag[id];
        minv[id<<1|1]+=tag[id];tag[id<<1|1]+=tag[id];
        tag[id]=0;
    }
    void pushup(int id){
        minv[id]=min(minv[id<<1],minv[id<<1|1]);
        num1[id]=num2[id]=0;
        if(minv[id<<1]==minv[id]) num1[id]+=num1[id<<1],num2[id]+=num2[id<<1];
        else if(minv[id<<1]==minv[id]+1) num2[id]+=num1[id<<1];
        if(minv[id<<1|1]==minv[id]) num1[id]+=num1[id<<1|1],num2[id]+=num2[id<<1|1];
        else if(minv[id<<1|1]==minv[id]+1) num2[id]+=num1[id<<1|1];
    }
    void build(int id,int l,int r){
        num1[id]=r-l+1;
        if(l==r) return;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
    }
    void upd(int id,int l,int r,int L,int R,int x){
        if(L<=l&&r<=R) {minv[id]+=x;tag[id]+=x;return;}
        if(tag[id]) pushdown(id);
        if(L<=mid) upd(id<<1,l,mid,L,R,x);
        if(R>mid) upd(id<<1|1,mid+1,r,L,R,x);
        pushup(id);
    }
    int ask(int id,int l,int r,int L,int R){
        if(L<=l&&r<=R) {
            if(minv[id]==1) return num1[id]+num2[id];
            if(minv[id]==2) return num1[id];
            return 0;
        }
        if(tag[id]) pushdown(id);
        int res=0;
        if(L<=mid) res+=ask(id<<1,l,mid,L,R);
        if(R>mid) res+=ask(id<<1|1,mid+1,r,L,R);
        return res;
    }
    #undef mid
}tr;

int main(){
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++) scanf("%d",&x),p[x]=i;
    LL ans=0;
    tr.build(1,1,n);
    for(int i=1;i<=n;i++){
        a[p[i]]=i;
        int x=a[p[i]-1],y=a[p[i]+1];
        if(x>y) swap(x,y);
        if(x) tr.upd(1,1,n,1,x,-1),tr.upd(1,1,n,y+1,i,1);
        else if(y) tr.upd(1,1,n,y+1,i,1);
        else tr.upd(1,1,n,1,i,1);
        ans+=tr.ask(1,1,n,1,i);
        //cout<<"->"<<ans<<endl;
    }
    ans-=n;
    cout<<ans<<endl;
    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/BakaCirno/p/12466819.html
Recomendado
Clasificación