El ganado de no intervención práctica partido 58 F

El significado de los problemas

Solicitar con un solo punto modificado entre cualesquiera dos puntos de la longitud de la trayectoria sub-árbol y XOR.
Todos longitud de camino igual y la ruta de XOR.

solución del problema

Simular sencilla qué se puede encontrar.
Un número impar, la respuesta es incluso puntos y XOR.
Con aún más baja, es normal y XOR.

XOR y puntos incluso también son fáciles de manejar.
Apunta a la profundidad de la paridad árbol de Fenwick.

Pero esto es para la cadena, no puede ser directamente re F s DFS secuencia, lo que se necesita dividida.
Pero yo no, así que para aprender un poco.

medios sencillos:
un nodo secundario de los más grandes sub-árbol como hijo pesada.
Cada prioridad hijo salía pesado, puede hacer re F s DFS secuencia de la cadena pesada son continuas.
Con esta característica, cuando tratamos a cada cabeza de la cadena de salto, y finalmente continuar el procesamiento de preguntar.

Este que: la complejidad de la cadena de árbol es dividida norte l la sol 2 norte n log ^ 2n
pero tengo dos preguntas:
¿Por qué es la complejidad de la garantía, y por qué saltar el primer salto, cuando la primera gran cadena o profundidad re F s DFS secuencia grande.

Pero ahora no es el punto, traté de conseguir la paloma (obligado a aprender la sección de árbol, recientemente, obviamente, estar en la teoría de grafos)

actualización de un solo punto, tres árboles segmento puede ser.

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn = 2e5+100;

vector<int>G[maxn];

int sz[maxn],son[maxn],dep[maxn];
int dfn[maxn],top[maxn],fa[maxn];
int A[maxn],cnt,n,m;

//剖分
void dfs1(int u,int pre){
    dep[u]=dep[pre]+1;
    sz[u]=1,fa[u]=pre;
    int s=0;
    for(auto v:G[u]){
        if(v==pre)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>s)son[u]=v,s=sz[v];
    }
}

void dfs2(int u,int tr_top){
    dfn[u]=++cnt;
    top[u]=tr_top;
    if(son[u])dfs2(son[u],tr_top);
    for(auto v:G[u]){
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}

//树状数组
int C[maxn][3];

int lowbit(int x){return (x&(-x));}
void change(int x,int d,int id){for(int i=x;i<=n;i+=lowbit(i))C[i][id]^=d;}
int query(int x,int id){if(x==0)return 0;int ret=0;for(int i=x;i;i-=lowbit(i))ret^=C[i][id];return ret;}

//树链剖分更新
void update(int x,int c){
    int val=A[x]^c;
    change(dfn[x],val,dep[x]%2);
    change(dfn[x],val,2);
    if(c)A[x]=c;
}

int query(int l,int r,int id){
    int ans=0,now;
    if(dep[l]%2!=dep[r]%2)now=2;
    else now=(dep[l]%2)^1;
    //cout<<id<<"?"<<endl;
    while(top[l]!=top[r]){
        if(dep[l]<dep[r])swap(l,r);
        ans^=query(dfn[l],now)^query(dfn[top[l]]-1,now);
      //  cout<<dfn[l]<<" "<<dfn[top[l]]-1<<endl;
        l=fa[top[l]];
    }
//    cout<<l<<" "<<r<<" "<<dep[l]%2<<" "<<dep[r]%2<<endl;
    if(dfn[l]<=dfn[r])ans^=query(dfn[r],now)^query(dfn[l]-1,now);
    else ans^=query(dfn[l],now)^query(dfn[r]-1,now);
    //cout<<dfn[l]<<" "<<dfn[r]<<endl;
    return ans;
}

int main(){
    cin>>n>>m;
    FOR(i,1,n)scanf("%d",&A[i]);
    FOR(i,1,n-1){
        int u,v;scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    FOR(i,1,n){
     //   cout<<i<<" "<<fa[i]<<" "<<sz[i]<<" "<<son[i]<<" "<<dep[i]<<" "<<dfn[i]<<" "<<top[i]<<endl;
    }
    FOR(i,1,n)update(i,0);
    FOR(i,1,m){
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1)update(l,r);
        else printf("%d\n",query(l,r,i));
    }
    //cout<<dfn[2]<<endl;
   // cout<<query(dfn[2],2)-query(dfn[2]-1,2)<<endl;
}

Publicados 203 artículos originales · ganado elogios 17 · Vistas a 20000 +

Supongo que te gusta

Origin blog.csdn.net/mxYlulu/article/details/104905974
Recomendado
Clasificación