題解 P6453 【[LNOI2014]LCA】
阿新 • • 發佈:2020-11-30
Solution [LNOI2014]LCA
題目大意:給定一棵樹,每次給定 \(l,r,z\),詢問 \(\sum_{i=l}^{r}dep[LCA(i,z)]\)
樹鏈剖分
分析:
關鍵性質在於,從根到兩個點的路徑的交,等於從根到它們的 \(LCA\) 的路徑。而一個點的深度,就相當於根到那個點的路徑長度。
因此原問題等價於每次對於 \(x \in [l,r]\),將根到 \(x\) 的路徑加 \(1\),然後詢問根到 \(z\) 的路徑上的權值之和。
這個可以離線下來,變成將 \(x \in [1,k]\) 的路徑加 \(1\),做個差分就可以了。
直接樹剖加上線段樹維護。
#include <cstdio> #include <cctype> #include <vector> #pragma GCC optmize(2) using namespace std; typedef long long ll; constexpr int maxn = 5e4 + 100,inf = 0x7fffffff,mod = 201314; inline int add(const int a,const int b){return (a + b) % mod;} inline int sub(const int a,const int b){return (a - b + mod) % mod;} inline int mul(const int a,const int b){return (1ll * a * b) % mod;} struct IO{//-std=c++11,with cstdio and cctype private: static constexpr int ibufsiz = 1 << 20; char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf; static constexpr int obufsiz = 1 << 20; char obuf[obufsiz + 1],*onow = obuf; const char *oed = obuf + obufsiz; public: inline char getchar(){ #ifndef ONLINE_JUDGE return ::getchar(); #else if(inow == ied){ ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin); *ied = '\0'; inow = ibuf; } return *inow++; #endif } template<typename T> inline void read(T &x){ static bool flg;flg = 0; x = 0;char c = getchar(); while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar(); while(isdigit(c))x = x * 10 + c - '0',c = getchar(); if(flg)x = -x; } template <typename T,typename ...Y> inline void read(T &x,Y&... X){read(x);read(X...);} inline int readi(){static int res;read(res);return res;} inline long long readll(){static long long res;read(res);return res;} inline void flush(){ fwrite(obuf,sizeof(char),onow - obuf,stdout); fflush(stdout); onow = obuf; } inline void putchar(char c){ #ifndef ONLINE_JUDGE ::putchar(c); #else *onow++ = c; if(onow == oed){ fwrite(obuf,sizeof(char),obufsiz,stdout); onow = obuf; } #endif } template <typename T> inline void write(T x,char split = '\0'){ static unsigned char buf[64]; if(x < 0)putchar('-'),x = -x; int p = 0; do{ buf[++p] = x % 10; x /= 10; }while(x); for(int i = p;i >= 1;i--)putchar(buf[i] + '0'); if(split != '\0')putchar(split); } inline void lf(){putchar('\n');} ~IO(){ fwrite(obuf,sizeof(char),onow - obuf,stdout); } }io; template <typename A,typename B> inline void chkmin(A &x,const B &y){if(y < x)x = y;} template <typename A,typename B> inline void chkmax(A &x,const B &y){if(y > x)x = y;} int n,q,ans[maxn]; namespace st{ #define ls (rt << 1) #define rs (rt << 1 | 1) struct node{ int sum,add; }tr[maxn << 2]; inline int calc(const int l,const int r){return r - l + 1;} inline void pushup(const int rt){tr[rt].sum = add(tr[ls].sum,tr[rs].sum);} inline void pushdown(const int rt,const int l,const int r){ tr[ls].add = add(tr[ls].add,tr[rt].add); tr[rs].add = add(tr[rs].add,tr[rt].add); int mid = (l + r) >> 1; tr[ls].sum = add(tr[ls].sum,mul(calc(l,mid),tr[rt].add)); tr[rs].sum = add(tr[rs].sum,mul(calc(mid + 1,r),tr[rt].add)); tr[rt].add = 0; } inline void modify(const int a,const int b,const int v,const int l = 1,const int r = n,const int rt = 1){ if(a <= l && b >= r){ tr[rt].add = add(tr[rt].add,v); tr[rt].sum = add(tr[rt].sum,mul(calc(l,r),v)); return; } pushdown(rt,l,r); const int mid = (l + r) >> 1; if(a <= mid)modify(a,b,v,l,mid,ls); if(b >= mid + 1)modify(a,b,v,mid + 1,r,rs); pushup(rt); } inline int query(const int a,const int b,const int l = 1,const int r = n,const int rt = 1){ if(a <= l && b >= r)return tr[rt].sum; pushdown(rt,l,r); int mid = (l + r) >> 1,res = 0; if(a <= mid)res += query(a,b,l,mid,ls); if(b >= mid + 1)res += query(a,b,mid + 1,r,rs); return res % mod; } #undef ls #undef rs } namespace tree{ vector<int> G[maxn]; inline void addedge(int u,int v){ // io.write(u,' '),io.write(v,'\n'); G[u].push_back(v);} int dfs_tot,dfn[maxn],rnk[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],faz[maxn]; inline void dfs1(const int u){ siz[u] = 1; for(int v : G[u]){ dep[v] = dep[u] + 1; dfs1(v); siz[u] += siz[v]; if(siz[v] > siz[son[u]])son[u] = v; } } inline void dfs2(const int u,const int tp){ dfn[u] = ++dfs_tot; rnk[dfs_tot] = u; top[u] = tp; if(son[u])dfs2(son[u],tp); for(int v : G[u]){ if(v == son[u])continue; dfs2(v,v); } } inline void modify(int u,const int v){ while(u){ st::modify(dfn[top[u]],dfn[u],v); u = faz[top[u]]; } } inline int query(int u){ int res = 0; while(u){ res = add(res,st::query(dfn[top[u]],dfn[u])); u = faz[top[u]]; } return res; } } struct oper{ int id,z,flg; }; vector<oper> vec[maxn]; int main(){ #ifndef ONLINE_JUDGE freopen("fafa.in","r",stdin); #endif tree::dep[1] = 1; io.read(n,q); for(int i = 2;i <= n;i++) tree::faz[i] = io.readi() + 1,tree::addedge(tree::faz[i],i); tree::dfs1(1); tree::dfs2(1,1); for(int l,r,z,i = 1;i <= q;i++){ io.read(l,r,z);l++,r++,z++; vec[l - 1].push_back(oper{i,z,-1}); vec[r].push_back(oper{i,z,1}); } for(int i = 1;i <= n;i++){ tree::modify(i,1); for(auto it : vec[i]) if(it.flg == 1)ans[it.id] = add(ans[it.id],tree::query(it.z)); else ans[it.id] = sub(ans[it.id],tree::query(it.z)); } for(int i = 1;i <= q;i++)io.write(ans[i],'\n'); return 0; }