1. 程式人生 > >【LCT+並查集】BZOJ2959[長跑]題解

【LCT+並查集】BZOJ2959[長跑]題解

題目概述

CHNJZ可以在 n 個地方虐場,每次虐場可以踩若干個人。一個地方的人被踩後就不能再踩了(心態已爆炸)。

m 個事件:1.地點 x 到地點 y 新建了一條邊。2.地點 x 能踩的人變成了 y 。3.詢問從 xy 最多能踩多少人。

解題報告

顯然是動態樹問題,可以用LCT解決。由於圖中會出現邊雙,不能重複計算,所以需要將邊雙縮點。

考慮合併 xy ,我們先取出 xy 的路徑,然後將路徑上所有權值都加到 y 上。接下來唯一的問題就是虛邊的 PathFather 發生了大量變化,很容易想到用並查集來解決這個問題。

示例程式

namespace:>9000ms,差點TLE。struct:6800ms。

為什麼namespace這麼慢啊QAQ!

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=150000;

int n,m,w[maxn+5],val[maxn+5];LL sum[maxn+5];
int son[maxn+5][2],fa[maxn+5];bool flip[maxn+5];
struct Dsu{
    int fa[maxn+5];
    void Clear() {for (int i=1;i<=n;i++) fa[i]=i;}
int getfa(int x) {if (fa[x]==x) return x;return fa[x]=getfa(fa[x]);} }A,B; #define Eoln(x) ((x)==10||(x)==13||(x)==EOF) inline char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); if (l==r) return EOF;return *l++; } inline int readi(int &x){ int tot=0,f=1;char ch=readc(),lst='+';
while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();} if (lst=='-') f=-f; while (isdigit(ch)) tot=(tot<<1)+(tot<<3)+(ch^48),ch=readc(); return x=tot*f,Eoln(ch); } #define fa(p) (B.getfa(fa[p])) #define is_ro(p) ((p)!=son[fa(p)][0]&&(p)!=son[fa(p)][1]) #define Son(p) ((p)==son[fa(p)][1]) inline void Pushup(int p) {sum[p]=sum[son[p][0]]+val[p]+sum[son[p][1]];} inline void Rotate(int t){ int p=fa(t),d=Son(t);son[p][d]=son[t][d^1];son[t][d^1]=p; Pushup(p);Pushup(t);if (!is_ro(p)) son[fa(p)][Son(p)]=t; if (son[p][d]) fa[son[p][d]]=p;fa[t]=fa(p);fa[p]=t; } inline void Addflip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;} inline void Pushdown(int p) {if (flip[p]) flip[p]^=1,Addflip(son[p][0]),Addflip(son[p][1]);} inline void Splay(int p){ static int top,stk[maxn+5];stk[top=1]=p; for (int i=p;!is_ro(i);i=fa(i)) stk[++top]=fa(i); while (top) Pushdown(stk[top--]); for (int pre=fa(p);!is_ro(p);Rotate(p),pre=fa(p)) if (!is_ro(pre)) Rotate(Son(p)==Son(pre)?pre:p); } inline void Access(int p) {for (int lst=0;p;lst=p,p=fa(p)) Splay(p),son[p][1]=lst,Pushup(p);} inline void Makero(int x) {Access(x);Splay(x);Addflip(x);} void Dfs(int x,int y){ if (son[x][0]) val[y]+=val[son[x][0]],Dfs(son[x][0],y); if (son[x][1]) val[y]+=val[son[x][1]],Dfs(son[x][1],y); B.fa[x]=y;son[x][0]=son[x][1]=0; } inline void Link(int x,int y){ int fx=A.getfa(x),fy=A.getfa(y); if (fx!=fy) {Makero(x);fa[x]=y;A.fa[fx]=fy;return;} Makero(x);Access(y);Splay(y);Dfs(y,y);Pushup(y); } inline LL Sum(int x,int y){ if (A.getfa(x)!=A.getfa(y)) return -1; Makero(x);Access(y);Splay(y);return sum[y]; } int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); readi(n);readi(m);A.Clear();B.Clear(); for (int i=1;i<=n;i++) readi(w[i]),val[i]=w[i],Pushup(i); for (int td,x,y;m;m--){ readi(td);readi(x);readi(y);int fx=B.getfa(x); if (td==1) x=fx,y=B.getfa(y),Link(x,y); else if (td==2) Makero(fx),val[fx]+=y-w[x],w[x]=y,Pushup(fx); else x=fx,y=B.getfa(y),printf("%lld\n",Sum(x,y)); } return 0; }