BZOJ4817[Sdoi2017]樹點塗色
阿新 • • 發佈:2018-12-10
傳送門
sdoi是真的舒服QAQ
比較神奇的資料結構上樹題233
我們觀察這個題的性質 發現將一條到1的路徑染色很像LCT的access操作 我們不妨將相同顏色的點放在一個splay裡面 然後access的時候 一條重邊變成輕邊的時候其實是 子樹內ans +1 可以理解成原來它和它上面的節點顏色原本是相同的 然後斷開邊表示顏色不同了 輕邊變成重邊 子樹內ans -1 原因同理 於是我們首先需要LCT來維持樹的結構
子樹內加減->我會dfs序上線段樹! 於是我們可以用線段樹維護子樹內答案 詢問3就變成了區間rmq
我們剩下了詢問2 詢問2怎麼做呢? 路徑問題! 樹上差分!
我們發現這個“權值”也是滿足樹上差分的性質的 我們可以對其維護它到1號點的ans記為f[i]
於是第二問的答案就是f[x]+f[y]-2*f[lca]+1 (比較神奇 無論lca的顏色是否存在在路徑上都是滿足這個差分的)
所以我們最後只需要LCT維護樹的形態 然後dfs序上線段樹維護f 單點查詢&區間查詢大小值即可QwQ
附程式碼。(我的程式碼真的好看233)
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define inf 20021225 #define mxn 100010 #define lson x<<1 #define rson x<<1|1 #define fa(x) t[x].fa #define ls(x) t[x].son[0] #define rs(x) t[x].son[1] #define not_root(x) (ls(fa(x))==x||rs(fa(x))==x) #define ll long long #define lg 18 using namespace std; struct node{int son[2],fa;bool rev;}t[mxn]; struct edge{int to,lt;}e[mxn<<1]; int in[mxn],cnt,dep[mxn],dfn[mxn],tot; int ff[mxn],n,sz[mxn],fa[mxn][lg+1],d[mxn]; struct Segtree { int mx[mxn<<2],tag[mxn<<2]; void pushup(int x){mx[x]=max(mx[lson],mx[rson]);} void pushdown(int x) { if(tag[x]) { mx[lson]+=tag[x]; tag[lson]+=tag[x]; mx[rson]+=tag[x]; tag[rson]+=tag[x]; tag[x]=0; } } void build(int x,int l,int r) { if(l==r){mx[x]=ff[d[l]];return;} int mid=(l+r)>>1; build(lson,l,mid);build(rson,mid+1,r); pushup(x); } void modify(int x,int l,int r,int LL,int RR,int v) { if(l>=LL&&r<=RR){mx[x]+=v;tag[x]+=v;return;} int mid=(l+r)>>1;pushdown(x); if(LL<=mid) modify(lson,l,mid,LL,RR,v); if(RR>mid) modify(rson,mid+1,r,LL,RR,v); pushup(x); } int query(int x,int l,int r,int LL,int RR) { if(l>=LL&&r<=RR) return mx[x]; int mid=(l+r)>>1,ans=0;pushdown(x); if(LL<=mid) ans=max(ans,query(lson,l,mid,LL,RR)); if(RR>mid) ans=max(ans,query(rson,mid+1,r,LL,RR)); return ans; } int getans(int x) { return query(1,1,n,dfn[x],dfn[x]); } }T; 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; } void rotate(int x) { if(!x||!not_root(x)) return; int f=fa(x),gf=fa(f); int k=rs(f)==x,p=k^1; if(not_root(f)) t[gf].son[t[gf].son[1]==f]=x; t[x].fa=gf;t[f].fa=x; t[f].son[k]=t[x].son[p]; if(t[x].son[p]) t[t[x].son[p]].fa=f; t[x].son[p]=f; } void splay(int x) { while(not_root(x)) { int f=fa(x),gf=fa(f); if(not_root(gf)) (rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f); rotate(x); } } int findroot(int x) { while(ls(x)) x=ls(x); return x; } void access(int x) { int y=0,w; do { splay(x); if(rs(x)) w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,1); t[x].son[1]=y; if(rs(x)) w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,-1); y=x;x=t[x].fa; }while(x); } void dfs(int x) { ff[x]=dep[x];dfn[x]=++tot;d[tot]=x;sz[x]=1;t[x].fa=fa[x][0]; for(int i=1;i<=lg;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=in[x];i;i=e[i].lt) { int y=e[i].to; if(dep[y]) continue; dep[y]=dep[x]+1;fa[y][0]=x; dfs(y);sz[x]+=sz[y]; } } int jump(int x,int len) { for(int i=0;i<=lg;i++) if(len&(1<<i)) x=fa[x][i]; return x; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); x=jump(x,dep[x]-dep[y]); if(x==y) return x; for(int i=lg;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int query(int x,int y) { return T.getans(x)+T.getans(y)-2*T.getans(lca(x,y))+1; } void modify(int x){access(x);} int qmax(int x) { return T.query(1,1,n,dfn[x],dfn[x]+sz[x]-1); } int main() { int m,x,y,opt; scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); } dep[1]=1;dfs(1);T.build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==1) { scanf("%d",&x); modify(x); } if(opt==2) { scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); } if(opt==3) { scanf("%d",&x); printf("%d\n",qmax(x)); } } return 0; }