(多校)校門外歪脖樹上的鴿子
阿新 • • 發佈:2021-11-06
先觀察題目性質
考慮形式化滿足哪些條件的點被選( update / query )
我們觀察一張圖:
對於上圖區間 \([3,10]\),選的的點依次為:\(14,5,6,7,8,17\)
其實就是我們把 \(l~r\) 點的樹上路徑拿下來
根據 \(lca\) 把樹分為兩部分
我們把左鏈和右鏈分開考慮
對於左鏈:
先對於節點 \(l\) ,我們找到 \(l\) 一直向右上跳的最遠位置(設其為 \(a\))
如果這個點不是 \(lca\) 【 我們需要對於是否會直接跳到 \(lca\) 分開考慮 】
那 \(a\) 就是其中一個被選點
對於 \(fa[a] - lca\) 這條鏈如果某節點為左兒子
那麼他的兄弟節點就為被選點
( 右鏈反之 ) ( 詢問與更改對應 )
Code
#include <bits/stdc++.h> #define re register #define int long long // #define ll long long // #define lls long long #define pir make_pair #define fr first #define sc second #define db double using namespace std; const int mol=993244853; const int maxn=5e5+10; const int INF=1e9+10; inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return (ans+mol)%mol; } inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); } return s*w; } int n,m,root,w[maxn]; bool isl[maxn],isr[maxn]; int backl[maxn],backr[maxn],bro[maxn]; struct DATE { int l,r,ll,rr; } dat[maxn]; struct STG { #define lid (id<<1) #define rid (id<<1|1) struct TREE { int sum,ks,lazy; } tre[maxn<<2]; int w[maxn]; inline void build(int id,int l,int r) { if(l==r) { tre[id].ks=w[l]; return ; } int mid=(l+r)>>1; build(lid,l,mid); build(rid,mid+1,r); tre[id].ks=tre[lid].ks+tre[rid].ks; } inline void push_down(int id) { int s=tre[id].lazy; tre[id].lazy=0; tre[lid].lazy+=s; tre[rid].lazy+=s; tre[lid].sum+=tre[lid].ks*s; tre[rid].sum+=tre[rid].ks*s; } inline void ins(int id,int l,int r,int ll,int rr,int val) { if(ll<=l&&r<=rr) { tre[id].lazy+=val; tre[id].sum+=val*tre[id].ks; return ; } if(tre[id].lazy) push_down(id); int mid=(l+r)>>1; if(ll<=mid) ins(lid,l,mid,ll,rr,val); if(rr>mid) ins(rid,mid+1,r,ll,rr,val); tre[id].sum=tre[lid].sum+tre[rid].sum; } inline int quy(int id,int l,int r,int ll,int rr) { if(ll<=l&&r<=rr) { return tre[id].sum; } if(tre[id].lazy) push_down(id); int mid=(l+r)>>1,ans=0; if(ll<=mid) ans+=quy(lid,l,mid,ll,rr); if(rr>mid) ans+=quy(rid,mid+1,r,ll,rr); return ans; } } trel,trer; int size[maxn],son[maxn],dep[maxn],fa[maxn]; int tot,dfn[maxn],top[maxn],eid[maxn]; inline void dfs1(int now) { size[now]=1; dep[now]=dep[fa[now]]+1; if(!backl[now]) backl[now]=now; if(!backr[now]) backr[now]=now; if(!dat[now].l&&!dat[now].r) { dat[now].ll=dat[now].rr=now; return ; } backr[dat[now].l]=backr[now]; dfs1(dat[now].l); size[now]+=size[dat[now].l]; backl[dat[now].r]=backl[now]; dfs1(dat[now].r); size[now]+=size[dat[now].r]; son[now]=size[dat[now].l]>size[dat[now].r]? dat[now].l:dat[now].r; w[dat[now].l]=(dat[dat[now].r].rr-dat[dat[now].r].ll+1); w[dat[now].r]=(dat[dat[now].l].rr-dat[dat[now].l].ll+1); dat[now].ll=dat[dat[now].l].ll; dat[now].rr=dat[dat[now].r].rr; } inline void dfs2(int now,int pre) { dfn[now]=++tot; eid[tot]=now; top[now]=pre; if(son[now]) dfs2(son[now],pre); else return ; if(dat[now].l!=son[now]) { dfs2(dat[now].l,dat[now].l); } if(dat[now].r!=son[now]) { dfs2(dat[now].r,dat[now].r); } } inline int getlca(int a,int b) { while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]]) swap(a,b); a=fa[top[a]]; } return dep[a]<dep[b]? a:b; } inline void wor(int a,int b,int d) { int lca=getlca(a,b); if(dep[backr[a]]<=dep[lca]&&dep[backl[b]]<=dep[lca]) { if(lca==root) w[lca]+=(dat[lca].rr-dat[lca].ll+1)*d; else if(isl[lca]) { trer.ins(1,1,tot,dfn[bro[lca]],dfn[bro[lca]],d); } else if(isr[lca]) { trel.ins(1,1,tot,dfn[bro[lca]],dfn[bro[lca]],d); } return ; } if(dep[backr[a]]<=dep[lca]) { a=dat[lca].l; if(isl[a]) { trer.ins(1,1,tot,dfn[bro[a]],dfn[bro[a]],d); } else if(isr[a]) { trel.ins(1,1,tot,dfn[bro[a]],dfn[bro[a]],d); } } else { a=backr[a]; if(isl[a]) { trer.ins(1,1,tot,dfn[bro[a]],dfn[bro[a]],d); } else if(isr[a]) { trel.ins(1,1,tot,dfn[bro[a]],dfn[bro[a]],d); } a=fa[a]; int lim=dat[lca].l; if(dep[a]>dep[lim]) { while(dep[top[a]]>dep[lim]) { trel.ins(1,1,tot,dfn[top[a]],dfn[a],d); a=fa[top[a]]; } if(dep[a]>dep[lim]) { int ls=top[dat[lim].l]==top[a]? dat[lim].l:dat[lim].r; trel.ins(1,1,tot,dfn[ls],dfn[a],d); } } } if(dep[backl[b]]<=dep[lca]) { b=dat[lca].r; if(isl[b]) { trer.ins(1,1,tot,dfn[bro[b]],dfn[bro[b]],d); } else if(isr[b]) { trel.ins(1,1,tot,dfn[bro[b]],dfn[bro[b]],d); } } else { b=backl[b]; if(isl[b]) { trer.ins(1,1,tot,dfn[bro[b]],dfn[bro[b]],d); } else if(isr[b]) { trel.ins(1,1,tot,dfn[bro[b]],dfn[bro[b]],d); } b=fa[b]; int lim=dat[lca].r; if(dep[b]>dep[lim]) { while(dep[top[b]]>dep[lim]) { trer.ins(1,1,tot,dfn[top[b]],dfn[b],d); b=fa[top[b]]; } if(dep[b]>dep[lim]) { int ls=top[dat[lim].l]==top[b]? dat[lim].l:dat[lim].r; trer.ins(1,1,tot,dfn[ls],dfn[b],d); } } } } inline int qus(int a,int b) { int lca=getlca(a,b),ans=0; if(dep[backr[a]]<=dep[lca]&&dep[backl[b]]<=dep[lca]) { if(lca==root) ans+=w[lca]; else if(isl[lca]) { ans+=trer.quy(1,1,tot,dfn[bro[lca]],dfn[bro[lca]]); } else if(isr[lca]) { ans+=trel.quy(1,1,tot,dfn[bro[lca]],dfn[bro[lca]]); } return ans; } if(dep[backr[a]]<=dep[lca]) { a=dat[lca].l; if(isl[a]) { ans+=trer.quy(1,1,tot,dfn[bro[a]],dfn[bro[a]]); } else if(isr[a]) { ans+=trel.quy(1,1,tot,dfn[bro[a]],dfn[bro[a]]); } } else { a=backr[a]; if(isl[a]) { ans+=trer.quy(1,1,tot,dfn[bro[a]],dfn[bro[a]]); } else if(isr[a]) { ans+=trel.quy(1,1,tot,dfn[bro[a]],dfn[bro[a]]); } a=fa[a]; int lim=dat[lca].l; if(dep[a]>dep[lim]) { while(dep[top[a]]>dep[lim]) { ans+=trel.quy(1,1,tot,dfn[top[a]],dfn[a]); a=fa[top[a]]; } if(dep[a]>dep[lim]) { int ls=top[dat[lim].l]==top[a]? dat[lim].l:dat[lim].r; ans+=trel.quy(1,1,tot,dfn[ls],dfn[a]); } } } if(dep[backl[b]]<=dep[lca]) { b=dat[lca].r; if(isl[b]) { ans+=trer.quy(1,1,tot,dfn[bro[b]],dfn[bro[b]]); } else if(isr[b]) { ans+=trel.quy(1,1,tot,dfn[bro[b]],dfn[bro[b]]); } } else { b=backl[b]; if(isl[b]) { ans+=trer.quy(1,1,tot,dfn[bro[b]],dfn[bro[b]]); } else if(isr[b]) { ans+=trel.quy(1,1,tot,dfn[bro[b]],dfn[bro[b]]); } b=fa[b]; int lim=dat[lca].r; if(dep[b]>dep[lim]) { while(dep[top[b]]>dep[lim]) { ans+=trer.quy(1,1,tot,dfn[top[b]],dfn[b]); b=fa[top[b]]; } if(dep[b]>dep[lim]) { int ls=top[dat[lim].l]==top[b]? dat[lim].l:dat[lim].r; ans+=trer.quy(1,1,tot,dfn[ls],dfn[b]); } } } return ans; } signed main(void) { freopen("pigeons.in","r",stdin); freopen("pigeons.out","w",stdout); n=read(); m=read(); for(re int i=1,a,b;i<n;i++) { dat[i+n].l=read(); dat[i+n].r=read(); bro[dat[i+n].l]=dat[i+n].r; bro[dat[i+n].r]=dat[i+n].l; fa[dat[i+n].l]=n+i; fa[dat[i+n].r]=n+i; isl[dat[i+n].l]=1; isr[dat[i+n].r]=1; } for(re int i=n+1;i<2*n;i++) if(!fa[i]) { root=i; break; } dfs1(root); dfs2(root,root); for(re int i=1;i<2*n;i++) { if(isl[i]) { trel.w[dfn[i]]=w[i]; } else if(isr[i]) { trer.w[dfn[i]]=w[i]; } } trel.build(1,1,tot); trer.build(1,1,tot); for(re int i=1,opt,l,r,d;i<=m;i++) { opt=read(); if(opt==1) { l=read(); r=read(); d=read(); wor(l,r,d); } else { l=read(); r=read(); printf("%lld\n",qus(l,r)); } } return 0; }