1. 程式人生 > >洛谷3690——樹鏈剖分模板

洛谷3690——樹鏈剖分模板

給定n個點以及每個點的權值,要你處理接下來的m個操作。操作有4種。操作從0到3編號。點從1到n編號。 0:後接兩個整數(x,y),代表詢問從x到y的路徑上的點的權值的xor和。保證x到y是聯通的。 1:後接兩個整數(x,y),代表連線x到y,若x到y已經聯通則無需連線。 2:後接兩個整數(x,y),代表刪除邊(x,y),不保證邊(x,y)存在。 3:後接兩個整數(x,y),代表將點x上的權值變成y。 輸入輸出格式 輸入格式: 第1行兩個整數,分別為n和m,代表點數和運算元。 第2行到第n+1行,每行一個整數,整數在[1,10^9]內,代表每個點的權值。 第n+2行到第n+m+1行,每行三個整數,分別代表操作型別和操作所需的量。 輸出格式: 對於每一個0號操作,你須輸出x到y的路徑上點權的xor和。 輸入輸出樣例 輸入樣例#1: 3 3 1 2 3 1 1 2 0 1 2 0 1 1 輸出樣例#1: 3 1 說明 資料範圍: 1

N1 \leq N,M3M \leq 3 105\cdot {10}^5

LCT板子題

各種錯誤搞得心力憔悴

// luogu-judger-enable-o2
#include<bits/stdc++.h> 
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
int n,m,val[300005],qn,lc[300005],rc[300005],fa[300005],xr[300005],q[300005],rev[300005];
inline void pushup(int x){xr[x]=xr[lc[x]]^xr[rc[x]]^val[x];}
inline void pushdown(int x){//下穿標記
        int l=lc[x],r=rc[x];
        if(rev[x]){
            rev[l]^=1;rev[r]^=1;rev[x]^=1;
            swap(lc[x],rc[x]);
        }
}
inline bool isr(int x)//判斷是否是實點
{
    return lc[fa[x]]!=x&&rc[fa[x]]!=x;
}
void rotate(int x){
    int y=fa[x],z=fa[y],l,r;
    if(lc[y]==x)l=0;else l=1;r=l^1;
    if(!isr(y)){if(lc[z]==y)lc[z]=x;else rc[z]=x;}
    if(lc[y]==x)
    {
    	fa[x]=z;fa[y]=x;fa[rc[x]]=y;
    	lc[y]=rc[x];rc[x]=y;
    }
    else
    {
        fa[x]=z;fa[y]=x;fa[lc[x]]=y;
    	rc[y]=lc[x];lc[x]=y;
    }	
    pushup(y);pushup(x);
}
inline void splay(int x)
{
    int top=1;q[top]=x;
    for(int i=x;!isr(i);i=fa[i])q[++top]=fa[i];
    for(int i=top;i;i--)pushdown(q[i]);
    while(!isr(x)){
        int y=fa[x],z=fa[y];
        if(!isr(y)){
            if((lc[y]==x)^(lc[z]==y))rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
inline void access(int x)//連線路徑
{
    for(int t=0;x;t=x,x=fa[x])
    splay(x),rc[x]=t,pushup(x);
}
inline void makeroot(int x)//換根
{
    access(x);
    splay(x);
    rev[x]^=1;
}
inline int findroot(int x)//找根節點
{
    access(x),splay(x);
    while(lc[x])pushdown(x),x=lc[x];
    return x;
}
void cut(int x, int y) {//切斷邊
    makeroot(x);
    if(findroot(y) == x && fa[x] == y && lc[y] == x && !rc[x]) { 
        fa[x] =lc[y] = 0;
        pushup(y);
    }
}
inline void link(int x,int y)//連邊
{
    makeroot(x);
    if(findroot(y)!=x)
    fa[x]=y;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)val[i]=read(),xr[i]=val[i];
    while(m--)
    {
        int op=read();
        if(op==0)
        {
            int x=read(),y=read();
            makeroot(x);access(y);splay(y);
            cout<<xr[y]<<'\n';
        }
        if(op==1)
        {
            int x=read(),y=read();
            int xx=findroot(x),yy=findroot(y);
            if(xx!=yy) link(x,y);
        }
        if(op==2)
        {
            int x=read(),y=read();
            cut(x,y);
        }
        if(op==3)
        {
            int x=read(),y=read();
            access(x),splay(x),val[x]=y,pushup(x);
        }
    }
}